Object.keysの型対応について
Object.keysの返り型がstring[]で配列に変換するときにエラーになってしまうので、keys自体に型をつけようと言う話。
code:typescript
const obj = {
a: 0,
b: 1,
c: 2,
} as const;
const items = Object.keys(obj).map((key) => objkey); // TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ readonly a: 0; readonly b: 1; readonly c: 2; }'.
// No index signature with a parameter of type 'string' was found on type '{ readonly a: 0; readonly b: 1; readonly c: 2; }'.
// 多分keyを 'a' | 'b' | 'c' のどれかにしてって意味だと思う
keysのメソッドを新しく作って解決
code:typescript
function typedKeys<T>(obj: T): Array<keyof T> {
return Object.keys(obj) as Array<keyof T>;
}
const items = typedKeys(obj).map((key) => objkey); 無理矢理解決した感があるので他に方法があれば是非教えて欲しいですm(_ _)m
(型情報最新だとObject.keysもやってくれるよ!とかでもいいです)
/icons/hr.icon
tamuraryoya.icon
汎用性は低下しますが、既存のObject.keys型の型定義を拡張して常に型安全にする方法もあります。
code:@types/global.d.ts
declare global {
interface ObjectConstructor {
keys<T>(o: T): Array<keyof T>;
}
}
これを定義すれば、どこでObject.keysを使おうと、常に返り値がArray<keyof T>となります。
onuma.icon
ありがとうございます!
汎用性は低下しますが
このワードが凄く気になるけど、もしかして拡張することによってよってObject.keysが使えなくなるパターンとかあったりしますか?
例えばany型のものを使ったときとか、中途半端な型定義によって変なところで型チェックエラーに遭うとか。
code:typescript
// 最初空オブジェクトで途中から要素が追加された時とか
Object.keys(obj).map((key) => {
console.log(key); // 型見るとneverになっていた
const a: string = key; // neverだから代入できない?🤔
});
tamuraryoya.icon
原理はわからないのですが、以下のような全然関係ない型を当てたときにany[]と推論されてしまったりしました。
code:ts
const obj = { a: 100, b: 200 } as const;
const foo = { c: 'a' } as const;
const keys = Object.keys(obj).map((k) => fook); // any[] おそらく、普通に使う分には影響ないと思います!
onuma.icon
了解です!とりあえずこれで試してみます😄
って思ったけど、なんか型の拡張が上手くいかなかったのでやっぱり普通にメソッドを作ります。。。
なんかglobalはexportやimportがないとダメですみたいなエラーで出たのでとりあえずexport {}とか書いて誤魔化してみたけど、差分ビルドすると一気に変になっちゃいました><
tamuraryoya.icon
グローバルの型定義ですが、どこからしらの@typesディレクトリ内にglobal.d.tsみたいな定義ファイルを作成して見てもらいたいです!
code:@types/global.d.ts
declare global {
interface ObjectConstructor {
keys<T>(o: T): Array<keyof T>;
}
}