Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript: How do you filter a type's properties to those of a certain type?

Tags:

typescript

I have a interface

export interface MyInterface {
    a: number;
    b: string;
    c: number;
}

I want to create a literal type of the property names for which value is of type number

I know how to get the type with all property names using

type MyType = keyof MyInterface // gives 'a'|'b'|'c'

I want to get just 'a'|'c'

like image 875
Labhansh Agrawal Avatar asked Dec 12 '25 18:12

Labhansh Agrawal


1 Answers

You certainly can define such a type in TypeScript:

type KeysMatching<T extends object, V> = {
  [K in keyof T]-?: T[K] extends V ? K : never
}[keyof T];

type MyType = KeysMatching<MyInterface, number>;
// type MyType = "a" | "c"

In this, KeysMatching<T, V> returns the set of keys of T whose properties are assignable to V. It uses a conditional and mapped type along with a property lookup. For each key K in keyof T, it checks whether T[K] is assignable to V. If so, it returns the key K; if not, it returns never. So for your types it would be something like {a: "a", b: never, c: "c"}. Then we look up the property values and get a union of the types like "a" | never | "c" which reduces to "a" | "c", exactly as you wanted.

Do note that KeysMatching<T, V> only returns those property keys whose values match V when reading the property. Those that are exactly V or a subtype of V:

interface AnotherInterface {
  narrower: 1;
  exact: number;
  wider: string | number;
}

type AnotherType = KeysMatching<AnotherInterface, number>;
// type AnotherType = "narrower" | "exact"

If you want to get the keys which match V when writing a property of T... that is, exactly V or a supertype of V, then you need a different implementation of KeysMatching:

type KeysMatchingWrite<T extends object, V> = {
  [K in keyof T]-?: [V] extends [T[K]] ? K : never
}[keyof T];

type AnotherTypeWrite = KeysMatchingWrite<AnotherInterface, number>;
// type AnotherTypeWrite = "exact" | "wider"

Anyway, hope that helps. Good luck!

Link to code

like image 175
jcalz Avatar answered Dec 14 '25 09:12

jcalz