Nika
Nika

Reputation: 1964

Why this indexed signature is failing?

I'm trying to get an object's values and make them as keys for the interface. Here's what I do:

const obj = {
    a: 'foo',
    b: 'bar',
} as const;

type A<T extends object, K extends keyof T = keyof T> = {
    [x: string]: T[K];
}[number];

// this one fails with:
// Type 'T[string]' is not assignable to type 'symbol'
type B<T extends object> = {
    [K in A<T>]: any;
};

// even if I do something like this, it still fails with the same error.
type C<T extends typeof obj = typeof obj> = {
    [K in A<T>]: any;
};

// this one works.
type D = {
    [K in A<typeof obj>]: any;
};

// this works, yay.
const a: D = {
    foo: 1,
    bar: 1,
};

I've never faced anything like this before, can somebody explain why this does not work? (or if there are any better ways to write it)?

Playground link

Upvotes: 0

Views: 42

Answers (2)

Aleksey L.
Aleksey L.

Reputation: 37938

The error says that it is not guaranteed that values of passed type are valid to be keys in a new type (Type 'T[string]' is not assignable to type 'string | number | symbol'). This can be fixed with appropriate generic constraint (e.g. T extends Record<PropertyKey, PropertyKey> instead of T extends object)

type ValuesAsKeys<T extends Record<PropertyKey, PropertyKey>> =
    Record<T[keyof T], any>;

const a: ValuesAsKeys<typeof obj> = {
    foo: 1,
    bar: 1,
};

Playground

Upvotes: 1

Paul Huynh
Paul Huynh

Reputation: 3140

You can extract the values from your object with the following type

type Values<T extends object> = T[keyof T]

Playground link

Upvotes: 1

Related Questions