ChatGPT解决这个技术问题 Extra ChatGPT

In TypeScript, what do "extends keyof" and "in keyof" mean?

In TypeScript, some types are defined using extends keyof or in keyof. I have tried to understand what they mean, but so far I didn't succeed.

What I got is that keyof alone returns a union type which has all the names as possible values that are existent as property names on the type that you specify after keyof.

type T = keyof string;

T therefor is equivalent to startsWith | endsWith | trim | substring | ....

Is this correct?

Now, if I try to think about what extends keyof and in keyof mean, my gut feeling says the following:

extends keyof is any type that derives from T, i.e. it has all these possible values, but maybe more.

in keyof is any type that takes values from T, but not necessarily all of them (it's possible, but maybe less).

So, from this POV extends keyof would describe a >= relation, in keyof would describe a <= relation. Is this correct? If not, what would be correct?


B
Bob Horn

For any type T, keyof T is the union of known, public property names of T.

Example:

interface Person {
  age: number;
  name: string;
}

type PersonKeys = keyof Person; // "age" | "name"

Your assumption that keyof string yields startsWith | endsWith | trim | ... is therefore correct. You can learn more about it in the lookup type release notes.

extends keyof

extends, in this case, is used to constrain the type of a generic parameter. Example:

<T, K extends keyof T>

K can therefore only be a public property name of T. It has nothing to do with extending a type or inheritance, contrary to extending interfaces.

A usage of extends keyof could be the following:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const person: Person = {
  age: 22,
  name: "Tobias",
};

// name is a property of person
// --> no error
const name = getProperty(person, "name");

// gender is not a property of person
// --> error
const gender = getProperty(person, "gender");

Aside from the documentation on index types, I found this helpful article.

in keyof

in is used when we're defining an index signature that we want to type with a union of string, number or symbol literals. In combination with keyof we can use it to create a so called mapped type, which re-maps all properties of the original type.

A usage of in keyof could be the following:

type Optional<T> = { 
  [K in keyof T]?: T[K] 
};

const person: Optional<Person> = {
  name: "Tobias"
  // notice how I do not have to specify an age, 
  // since age's type is now mapped from 'number' to 'number?' 
  // and therefore becomes optional
};

Aside from the documentation on mapped types, I once again found this helpful article.

Fun fact: The Optional type we've just built has the same signature as the official Partial utility type!


Thanks for the answer. I was stuck on the concept of extends keyof. They really should have chosen a different keyword for this situation. This is really confusion and counter-ituitive. From the doc: T extends Lengthwise and K extends keyof T where the extends keyword means something completely different.
Does it mean, the extends is always used for generic, in is always for the index assessor?
@JunleLi yes, you can't use them the other way around. Sorry for the late response, I seem to have missed your comment!
@cbdeveloper A extends B means "some A that is a subtype of B" for both. If B is a keyof type, then A is one string from the set --- and the type checker can say more about code that uses this one string thanks to indexed access types.
Much clearer explanation than given by the otherwise pretty awesome official handbook.