简体   繁体   中英

In TypeScript, can I restrict type of indexer value based on narrow type of indexer key?

Simple example (type of x ):

const x = {
    'a': { key: 'a' },
    'b': { key: 'b' },
    'c': { key: 'c' },
    // ...
};

If I knew all a / b / c / in advance, I could do { [TKey in 'a'|'b'|'c']: { key: TKey } } .

But can I define a type so that for any key k value must have { key: k } without having a full list of keys in advance?

You can let the compiler message guide you:

This is what you would like:

type Foo<K> = { [TKey in K]: { key: TKey } }

but it doesn't compile because

Type 'K' is not assignable to type 'string | number | symbol'.
  Type 'K' is not assignable to type 'symbol'.

Assuming (based on your example) you want to work only with string keys:

type Foo<K extends string> = { [TKey in K]: { key: TKey } }

So you can pass your own narrowed type that's based on string:

type X = Foo<'a' | 'b' | 'c'>
type X = {
    a: {
        key: "a";
    };
    b: {
        key: "b";
    };
    c: {
        key: "c";
    };
}

I've been searching for this as well. I experimented in TypeScript a bit and came up with this solution:

type ObjectWithKey<obj extends {[key: string]: any}> = {
  [k in keyof obj]: {key: k};
}

declare function createObjectWithKeys<T extends {[key: string]: any} & ObjectWithKey<T>>(input: T): T;

// This does not compile
const x = createObjectWithKeys({
    a: 1,
    b: {key: 'c'},
    c: {key: false}
})

// This does compile
const x = createObjectWithKeys({
    a: {key: 'a'},
    b: {key: 'b'},
    c: {key: 'c'}
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM