型を定義していると一例ですが、次のような場面に遭遇したことはないでしょうか?
const VideoPlayer: React.VFC<Props> = ({ url, manifestUrl }) //VideoPlayerはurl or manifestUrlで再生できる => { return ( //... 省略 ... ); }; <VideoPlayer url={url} manifestUrl={manifestUrl}/> //両方受け取りたくない //両方受け取った場合、TypeErrorを出したい
普通に何も考えずにpropsの型定義すれば以下のようになるでしょう。
type props = { url?:stiring; manifestUrl?: string; };
しかし、このように書いてしまうとurl
とmanifestUrl
両方指定することができますよね。
両方指定した場合は、TypeErrorを出すようにしたいですね。
ということで、以下のように実装してみます。
type WithManifestUrl = { url?: never; manifestUrl: string; }; type WithUrl = { url: string; manifestUrl?: never; }; type Props = WithManifestUrl | WithUrl;
こうすることで
<VideoPlayer url={url} manifest={manifestUrl}> // Type '{ url: string; manifestUrl: string; }' is not assignable to type '(IntrinsicAttributes & A) | (IntrinsicAttributes & //B)'. // Type '{ url: string; manifestUrl: string; }' is not assignable to type 'B'. <VideoPlayer url={url} > //OK <VideoPlayer manifest={manifestUrl}> //OK
タイプエラーが出でくれましたね。
しかしこう書いたからといってVideoPlayer
コンポーネント内でTypeScriptは「url
が定義されている場合は、manifestUrl
はundefined
だ」ということを普通には理解してくれません。
以下のように書いてみましょう
const MediaPlayer: React.VFC<Props> = (props) => { let content: string; if (props.url !== undefined) { content = props.url; } else { content = props.manifestUrl; } return ( <div className="App"> <h1>{content}</h1> </div> ); };
そうすることで、else以下のmanifestUrl
がstring
型であることが型推論によって補完されています
ここでポイントなのは({url,manifestIrl}}
としないことです。
Propsを展開してしまうと、manifestUrlとurlの型が確定しまい、props型での型推論のサポートがなくなり上のような挙動にはならないのです。
まとめ
指定したくない型をnever
にするかundefined
にすればいいかはわからないので教えてくださいmm
短いですがおわり