続 keyof T
keyof Tを用いて連想配列でアクセスする際の縛りを前に書きましたが、もっとスマートな書き方を思いついたのでメモ。
test ('power of keyof', () => { function checkObject<T>(props: T): { [N in keyof T]?: string } { return Object.keys(props).reduce( (prior, key) => { // propsを型変換するのではなく、連想配列キーを「as keyof」でTへ縛る。 const value = props[key as keyof T]; if (typeof value === 'number' && value > 0) { return prior; } return { ...prior, [key]: `${key} is invalid.` }; }, {}, ); } type Target = { first: string, second: number, third: number, fourth: boolean, }; const target: Target = { first: '', second: 10, third: -3, fourth: true }; const result = checkObject<Target>(target); expect(result.first).toBe('first is invalid.'); });
変えたのは一箇所で、props[key as keyof T]のとこ。propsを「as { [key: string]: any }」で型変換するのではなく、連想配列キーを「as keyof」でTへ縛る。この応用で、関数の引数とかで、name: stringがあったときに、name: keyof Tというのも有用かと思います。
function foo<T>(obj: T, name: keyof T): any { return T[name]; }
コードとしてはあまり意味がないけど、これでしょうがなくanyで受けてたところが改善されます。