TypeScriptの `keyof`に似た` valueof`はありますか?


119

キーと値を入力として与えられた値にオブジェクトプロパティを割り当てることができ、それでも値のタイプを判別できるようにしたい。説明するのが少し難しいので、このコードは問題を明らかにするはずです:

type JWT = { id: string, token: string, expire: Date };
const obj: JWT = { id: 'abc123', token: 'tk01', expire: new Date(2018, 2, 14) };

function print(key: keyof JWT) {
    switch (key) {
        case 'id':
        case 'token':
            console.log(obj[key].toUpperCase());
            break;
        case 'expire':
            console.log(obj[key].toISOString());
            break;
    }
}

function onChange(key: keyof JWT, value: any) {
    switch (key) {
        case 'id':
        case 'token':
            obj[key] = value + ' (assigned)';
            break;
        case 'expire':
            obj[key] = value;
            break;
    }
}

print('id');
print('expire');
onChange('id', 'def456');
onChange('expire', new Date(2018, 3, 14));
print('id');
print('expire');

onChange('expire', 1337); // should fail here at compile time
print('expire'); // actually fails here at run time

に変更value: anyしてみましたvalue: valueof JWTが、うまくいきませんでした。

は日付タイプではないonChange('expire', 1337)ため、理想的には失敗し1337ます。

value: any特定のキーの値に変更するにはどうすればよいですか?

回答:


220

更新:質問のタイトルは、可能なすべてのプロパティ値タイプの結合を探している人々を引き付けているように見えkeyofます。これは、可能なすべてのプロパティキータイプの結合を提供する方法に似ています。最初にそれらの人々を助けましょう。次のようにキーとしてルックアップタイプを使用することにより、にValueOf類似させることができます。keyofkeyof T

type ValueOf<T> = T[keyof T];

それはあなたに与える

type Foo = { a: string, b: number };
type ValueOfFoo = ValueOf<Foo>; // string | number

上記の質問については、個々のキー(より狭い)を使用して、必要なkeyof T値タイプのみを抽出できます。

type sameAsString = Foo['a']; // lookup a in Foo
type sameAsNumber = Foo['b']; // lookup b in Foo

キーと値のペアが関数で適切に「一致する」ことを確認するには、次のようにジェネリックとルックアップタイプを使用する必要があります。

declare function onChange<K extends keyof JWT>(key: K, value: JWT[K]): void; 
onChange('id', 'def456'); // okay
onChange('expire', new Date(2018, 3, 14)); // okay
onChange('expire', 1337); // error. 1337 not assignable to Date

この考え方keyにより、コンパイラは汎用Kパラメータを推測できます。次に、valuematches JWT[K]、つまり必要な検索タイプが必要です。

お役に立てば幸いです。幸運を!


tuplefrom値を作成したい。それをする機会はありますか?
— Morteza Tourani

これは無関係な質問のように聞こえるので、おそらくどこか他の場所で質問する必要があります。最小限の再現可能な例を使用して、人々があなたのユースケースを確実に理解できるようにしてください。幸運を。
— jcalz

1
関数メンバーを持つ文字列値の列挙型を使用して問題に遭遇しました。これをうまく処理するには、を使用できますtype StringValueOf<T> = T[keyof T] & string;。文字列列挙型で見つけた最高のドキュメントは、TypeScript 2.9リリースノート
— karmakaze

41

誰かがまだvalueof何らかの目的での実装を探しているなら、これは私が思いついたものです:

type valueof<T> = T[keyof T]

使用法:

type actions = {
  a: {
    type: 'Reset'
    data: number
  }
  b: {
    type: 'Apply'
    data: string
  }
}
type actionValues = valueof<actions>

期待どおりに動作します:)可能なすべての型のユニオンを返します


2
これはいいね。それは私の他の問題をほぼ解決しますが、スイッチはタイプをまったく絞り込んでいないようです。
— スタイル

作りたい tuplefrom値。それをする機会はありますか?
— Morteza Tourani

12

オブジェクトの共用体タイプを抽出する別の方法があります。

  const myObj = { a: 1, b: 'some_string' } as const;
  type values = typeof myObj[keyof typeof myObj];

結果: 1 | "some_string"


これconstは非常に貴重です。TypeScriptは実際に値を提供し、重複を削除します。辞書にはとても良いです。
— ノーム

まさに私が探していたもの!
— Mavrick RMX '

2

問題を完全に解決する既存の回答に感謝します。この一般的なタイプをインポートしたい場合は、ライブラリを追加したかっただけで、このユーティリティタイプが含まれています。

https://github.com/piotrwitek/utility-types#valuestypet

import { ValuesType } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
// Expect: string | number | boolean
type PropsValues = ValuesType<Props>;

2

これを試して:

type ValueOf<T> = T extends any[] ? T[number] : T[keyof T]

配列またはプレーンオブジェクトで機能します。

// type TEST1 = boolean | 42 | "heyhey"
type TEST1 = ValueOf<{ foo: 42, sort: 'heyhey', bool: boolean }>
// type TEST2 = 1 | 4 | 9 | "zzz..."
type TEST2 = ValueOf<[1, 4, 9, 'zzz...']>

0

一発ギャグ:

type ValueTypesOfPropFromMyCoolType = MyCoolType[keyof MyCoolType];

ジェネリックメソッドの例:

declare function doStuff<V extends MyCoolType[keyof MyCoolType]>(propertyName: keyof MyCoolType, value: V) => void;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.