gl-react
でお絵描き的なことをしようとしてて、Typescript
の型チェックが通らない値を設定する必要が出来た。
型設定を修正するのが正攻法ですが、直すのが面倒な事情もあっていくつかのプロパティーの型チェックを放棄したい。
考えてみれば必要な機能で基本的な事なんですが、やろうと思ったことがなかったので知らなかった。
きっかけ
<Node>
の clear
プロパティに null
を設定する必要がある。
ただドキュメントには option
引数となってるし定義も以下のようになっている。
1 2 3 4 5 6 7 |
export type Vec4 = [number, number, number, number]; export interface NodeProps { ... clear?: { color: Vec4; }; }; |
これだと長さが4の数値配列か undefined
しか設定できない。
テストコードと解決方法
問題を簡潔化するためにこんなコードを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const App = () => { return <Child prop1="test" prop2={[1, 2]}></Child>; }; type ChildProps = { prop1: string; prop2?: [number, number]; }; const Child = ({ prop1, prop2 }: ChildProps) => { return ( <div> <p>{prop1.toString()}</p> <p>{prop2 && prop2.toString()}</p> </div> ); }; export default App; |
prop1
は文字列が必要ですし、prop2
は指定なしか配列が必要です。
この制約を破るには any
型として宣言することで、型チェックを免除させます。
1 2 3 4 5 |
return <Child prop1="test" prop2={null as any}></Child>; //あるいは const prop2: any = null; return <Child prop1="test" prop2={prop2}></Child>; |
スプレット演算子を使って any
型オブジェクトを渡せば、プロパティを省略しようが増やそうがもうなんでもいけます。
1 2 3 4 5 6 |
//型エラー:prop1がないし、prop3なんていらない <Child prop2={null as any} prop3={"surplus" as any}></Child> //型チェックは通る const props: any = { prop2: null, prop3: "surplus" }; return <Child {...props}></Child>; |
ただし{prop1.toString()}
で実行エラー 'toString' of undefined
が起きます。
なんでもできるということは Typescript
の利点を投げ捨てるということなので、型の修正が困難で、安全かつ他に影響が出ない場合のみにしましょう。
中間コンポーネントを用意するとコントロールしやすいです。
1 2 3 4 5 6 7 |
type MidProps = { prop1: string; prop2?: any; }; const Mid = (props: MidProps) => { return <Child {...props}></Child>; }; |
きっかけとなった <Node>
もこんな感じで rest
をそのまま詰め込んでます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
type Props = { children?: any; t?: any; clear?: any; blendFunc?: any }; const App = ({ children, t, ...rest }: Props) => { const { drawing, center } = React.useContext(Context); const uniforms: uniforms = {}; uniforms.t = t || defaultTexture; uniforms.drawing = drawing; uniforms.color = [0.3, 0.3, 0.3, 1]; uniforms.center = center; uniforms.brushRadius = 0.1; return ( <Node shader={shaders.Paint} uniforms={uniforms} {...rest}> {children} </Node> ); }; |