web-dev-qa-db-ja.com

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

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

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: anyvalue: valueof JWTに変更しようとしましたが、うまくいきませんでした。

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

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

64
styfle

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

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

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

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パラメーターを推測できます。次に、valueJWT[K](必要なルックアップタイプ)と一致する必要があります。

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

93
jcalz

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

type valueof<T> = T[keyof T]

使用法:

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

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

31
Chris Kowalski