TypeScript'te "keyof" a benzer bir "valueof" var mı?


119

Girdi olarak bir anahtar ve değer verilen bir değere bir nesne özelliği atayabilmek, ancak yine de değerin türünü belirleyebilmek istiyorum. Açıklaması biraz zor, bu yüzden bu kod sorunu ortaya çıkarmalı:

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

Ben değiştirmeyi denedi value: anyetmek value: valueof JWTama bu işi yoktu.

İdeal olarak, Tarih türü olmadığı için onChange('expire', 1337)başarısız olur 1337.

value: anyVerilen anahtarın değerini nasıl değiştirebilirim ?

Yanıtlar:


224

GÜNCELLEME: Görünüşe göre soru başlığı, tüm olası özellik değeri türlerinin bir birleşimini arayan insanları çekiyor, buna benzer şekilde keyof, size tüm olası özellik anahtarı türlerinin birleşimini vermesine benzer . Önce bu insanlara yardım edelim. Bir yapabilir ValueOfbenzer keyofkullanarak, türlerini araması ile keyof Tşöyle, anahtar olarak:

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

sana veren

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

Belirtildiği gibi soru için, keyof Tyalnızca ilgilendiğiniz değer türünü çıkarmak için daha dar olan tek tek anahtarları kullanabilirsiniz :

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

Bir işlevde anahtar / değer çiftinin doğru bir şekilde "eşleştiğinden" emin olmak için, aşağıdaki gibi arama türlerinin yanı sıra jenerikleri de kullanmalısınız :

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

Buradaki fikir, keyparametrenin derleyicinin genel Kparametreyi çıkarmasına izin vermesidir . Ardından , ihtiyacınız olan arama türü olan valueeşleşmeleri gerektirir JWT[K].

Umarım yardımcı olur; iyi şanslar!


tupleDeğerlerden bir yaratmak istiyorum . Bunu yapma şansı var mı?
Morteza Tourani

Bu, ilgisiz bir soru gibi görünüyor, bu yüzden muhtemelen başka bir yere, minimum tekrarlanabilir bir örnekle sormalısınız, böylece insanlar kullanım durumunuzu anlayacaklardır. İyi şanslar.
jcalz

1
İşlev üyeleriyle dizge değerli bir enum kullanarak bir sorunla karşılaştı. Bunu iyi halletmek için kullanabilirsiniz type StringValueOf<T> = T[keyof T] & string;. Dize numaralandırmalarında bulduğum en iyi belgeler TypeScript 2.9 sürüm notları
karmakaze

41

Hala valueofherhangi bir amaç için uygulanmasını isteyen biri varsa , bu benim bulduğum bir şey:

type valueof<T> = T[keyof T]

Kullanımı:

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

Beklendiği gibi çalışıyor :) Olası tüm türlerin birliğini döndürür


2
Bu güzel. Neredeyse diğer sorunumu çözüyor , ancak anahtar türü hiç daraltmıyor gibi görünüyor.
styfle

tupleDeğerlerden bir yaratmak istiyorum . Bunu yapma şansı var mı?
Morteza Tourani

12

Nesnenin birleşim türünü çıkarmanın başka bir yolu var:

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

Sonuç: 1 | "some_string"


Bu constşey çok değerlidir, TypeScript aslında değerleri kendileri sağlar ve kopyaları kaldırır; Sözlükler için çok iyidir.
Noam

Tam olarak aradığım şey!
Mavrick RMX '21

2

Sorunu mükemmel bir şekilde çözen mevcut cevaplara teşekkürler. Sadece bir kütüphane eklemek istedim, eğer bu yaygın olanı içe aktarmayı tercih ediyorsanız, bu yardımcı program türünü dahil etti.

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

Bunu dene:

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

Bir dizi veya düz bir nesne üzerinde çalışır.

// 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

Tek astarı:

type ValueTypesOfPropFromMyCoolType = MyCoolType[keyof MyCoolType];

Genel bir yöntem örneği:

declare function doStuff<V extends MyCoolType[keyof MyCoolType]>(propertyName: keyof MyCoolType, value: V) => void;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.