Open RyanCavanaugh opened 2 years ago
related: #30728
Collecting more
Note to self for future ease of searching: I usually call KeysOfType<O, T>
by the name KeysMatching<T, V>
Sure would be nice to see this implemented! The KeysMatching
approach doesn't work when used on the base of a derived class, e.g.:
type KeysMatching<Target, Type> = {
[Key in keyof Target]: Target[Key] extends Type ? Key : never
}[keyof Target];
class Animal {
breathe() {
console.log(`Ahh`);
}
exec(methodName: KeysMatching<this, Function>) {
(this[methodName] as Function)();
}
}
class Cat extends Animal {
constructor() {
super();
this.exec(`meow`); // Argument of type 'string' is not assignable to parameter of type 'KeysMatching<this, Function>'.
}
meow() {
console.log(`Meow`);
}
}
@RobertAKARobin actually that doesn't even work on the base class. This does though: Playground Link
class Animal {
breathe() {
console.log(`Ahh`);
}
exec<T extends Record<MethodName, Function>, MethodName extends keyof T>(this: T, methodName: MethodName) {
(this[methodName] as Function)();
}
}
class Cat extends Animal {
a = 1;
constructor() {
super();
this.exec(`breathe`);
}
meow() {
console.log(`Meow`);
}
}
Another issue that maybe related to this
In the following, in usetest2, Test2
interface Test {
a: boolean;
b?: boolean;
c: undefined;
d?: string;
e: number;
}
interface TestGeneric<T> extends Test {
f: T;
g: T[];
}
type BooleanKey<T, K extends keyof T = keyof T> = K extends any ? T[K] extends (boolean|undefined) ? (T[K] extends undefined ? never : K) : never : never;
type BooleanKeys<T> = {
[K in keyof T]-?: T[K] extends (boolean | undefined) ? (T[K] extends undefined ? never : K) : never;
}[keyof T];
type t1 = BooleanKey<Test>;
type t2 = BooleanKeys<Test>;
type NonNullableBoolOnlyFields<T> = {
[K in BooleanKeys<T>]-?: boolean;
};
type NonNullableBools<T> = T & NonNullableBoolOnlyFields<T>;
type Test1 = NonNullableBools<Test>
type Test2<T> = NonNullableBools<TestGeneric<T>>
type Field = 'e';
function test1(p1: Test1[Field]): number {
const result: number = p1;
return result;
}
function usetest1() {
return test1(10);
}
function test2<T>(p1: Test2<T>[Field]): number {
const result: number = p1;
return result;
}
function usetest2<T>() {
return test2<T>(10);
}
Suggestion
🔍 Search Terms
keyof property keysOfType
✅ Viability Checklist
My suggestion meets these guidelines:
⭐ Suggestion
We frequently get people writing definitions to produce the keys
K
of an object typeO
whereO[K] extends T
. Let's call this operationKeysOfType<O, T>
. Varying userland definitions includeThese userland definitions work in concrete cases, but can't be used to write generic functions:
We could add a new type operator or intrinsic alias
KeysOfType<T, P>
that returns allkeyof T
K
such thatT[K] extends P
. When this type indexes a generic object of typeT
, we can then know thatT[KeysOfType<T, P>]
is assignable toP
. In non-generic positions, this can be immediately resolved the same way as the userland definition.📃 Motivating Example
See
getString
above💻 Use Cases
This is a frequent complaint; need link more inbound issues here
48989