タイプスクリプト:タイプ狭まりの話
何をしますか.
私の最初の試みは、APIからデータを共通の形式に再マップすることです.それから、私はそれが本当にそれらのデータを統一するのが難しいと理解します.それで、私はこのコードを思いつきます.
type SomeKindOfInterfaceHere = { hello: string };
type AnotherInterface = { world: boolean };
interface MappedDataFromApi {
id: string | number;
data: string[] | SomeKindOfInterfaceHere | AnotherInterface;
}
function AReactComponent(props: MappedDataFromApi) {
if (props.data.hello) {
return <>display {props.data.hello} </>
}
if (props.data.world) {
return <>display {props.data.world} </>
}
return props.data.map(d => (<>display array item: {d}</>));
}
それは完全に動作します.事態は晴れる.しかし、スクリプトは叫んで起動し、コードをコンパイルするのを防ぎます.Property ‘hello’ does not exist on type >‘SomeKindOfInterfaceHere | AnotherInterface | string[]’.
Property ‘hello’ does not exist on type ‘AnotherInterface’.(2339)
タイプスクリプトを満足させるために、私は私のコードをこれに直します
interface MappedDataFromApi {
id: string | number;
contentVR?: SomeKindOfInterfaceHere;
documentsInfo?: string[];
bundleInfo?: AnotherInterface;
}
function AReactComponent(props: MappedDataFromApi) {
if (props.contentVR) {
return <>display {props.contentVR.hello} </>
}
if (props.bundleInfo) {
return <>display {props.bundleInfo.world} </>
}
return props.documentsInfo && props.documentsInfo.map(d => (<>display array item: {d}</>));
}
もちろん、typescriptは今より良い感じがすることができます.私たちは別の問題を引き起こしました.Hey mate, this interface is bad. It has so many
?
It is arbitrary. How can I re-use it elsewhere? How can I maintain your code once you not here? Those properties look mysterious.
残酷だが合理的!
OK、もう一度試してみましょう.私はインターフェイスを小さい部分に分けます.それはきちんとしたように見えます
?
, でも.interface VerificationRequest {
uuid: string;
content: SomeKindOfInterfaceHere;
}
interface SingleVerification {
id: number;
documents: string[];
}
interface Bundle {
id: number;
info: AnotherInterface;
}
type MappedDataFromApi = VerificationRequest | SingleVerification | Bundle;
function AReactComponent(props: MappedDataFromApi) {
if (props.content) {
return <>display {props.content.hello} </>
}
if (props.info) {
return <>display {props.info.world} </>
}
return props.documents.map(d => (<>display array item: {d}</>));
}
BRRRRRは、typescript再び私と同じ問題を前に叫ぶ.Property ‘content’ does not exist on type ‘MappedDataFromApi’.
Property ‘content’ does not exist on type ‘SingleVerification’.(2339)
幸運にも、TypeScriptは、より良いコードを書いて、このケースで良いタイピングをするのを助けるために、これらの宝石を持っています.
型述語の使用
このメソッドを使用すると、私はどんな種類のインターフェイスを検出するかを検出するユーティリティ機能を追加することができます.コードはこのようになります.
function isVerificationRequest(props: MappedDataFromApi): props is VerificationRequest {
return !!(props as VerificationRequest).content;
}
function isSingleVerification(props: MappedDataFromApi): props is SingleVerification {
return Array.isArray((props as SingleVerification).documents);
}
function isBundle(props: MappedDataFromApi): props is Bundle {
return !!(props as Bundle).info;
}
function AReactComponent(props: MappedDataFromApi) {
if (isVerificationRequest(props)) {
return <>display {props.content.hello} </>
}
if (isBundle(props)) {
return <>display {props.info.world} </>
}
return props.documents.map(d => (<>display array item: {d}</>));
}
美しい、右?👏👏👏つのことは、このスタイルが私の最終的なJSコードサイズを少しより大きくするということです.あなたは、タイプスクリプト遊び場の上でJSコンパイル版をチェックすることができます.
差別労働組合
このメソッドを使用すると、リテラル型の共通プロパティをインターフェイスに追加できます.コードはこのようになります.
interface VerificationRequest {
uuid: string;
content: SomeKindOfInterfaceHere;
kind: 'verification-request';
}
interface SingleVerification {
id: number;
documents: string[];
kind: 'single-verification';
}
interface Bundle {
id: number;
info: AnotherInterface;
kind: 'bundle';
}
type MappedDataFromApi = VerificationRequest | SingleVerification | Bundle;
function AReactComponent(props: MappedDataFromApi) {
switch (props.kind) {
case 'verification-request':
return <>display {props.content.hello} </>
case 'single-verification':
return props.documents.map(d => (<>display array item: {d}</>));
case 'bundle':
return <>display {props.info.world} </>
default:
return null;
}
}
それもきちんと見えます.あなたも作ることができますExhaustiveness checking このスタイルで.一方、他のインターフェイスを再利用したい場合は、共通のプロパティを省略するか、手動でデータコレクションに追加する必要があります.そうでなければ、もう一度あなたに叫んでください.ここに私が話していることがあります.
// drop "kind" by create a new Omit type
type NewSingleVerification = Omit<SingleVerification, "kind">
function getSingleVerification(): NewSingleVerification {
return {
id: 1,
documents: ['education', 'license'],
};
}
// OR
function getSingleVerification(): SingleVerification {
return {
id: 1,
documents: ['education', 'license'],
// manual add this
kind: 'single-verification',
};
}
これは、UIの問題をビジネスロジックのどこにする必要はありませんので、私にとっては巨大な欠点です.結論
これらは私が思い付くすべての解決策です.それぞれが自分の欠点を持っていますが、少なくとも最後の2はタイプチェックについてほとんど私のチームの懸念をカバーすることができます、そして、誰でも簡単にコードを理解することができます.
あなたが他の解決策を持っているならば、下記をコメントしてください.
読書ありがとう
Reference
この問題について(タイプスクリプト:タイプ狭まりの話), 我々は、より多くの情報をここで見つけました https://dev.to/quanpham/typescript-a-narrowing-type-story-19g3テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol