-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wrong keyof behaviour for generic with extends types in 2.9 #24560
Comments
This is also true for function-bound generics:
|
|
Huh, interesting, how is that different from using a bare
If T is |
Is this the same issue? type FormFields = { someField: string };
// Typescript should allow only keys of "FormFields" to be
// used as fieldName
class GenericForm<T extends FormFields> {
public fieldA = new FormField<T>({ fieldNameA: "someField" }); // works as expected
public fieldB = new FormField<T>({ fieldNameB: "someField" }); // throws an error
}
interface FormFieldOptions<T extends FormFields> {
fieldNameA?: keyof T;
fieldNameB?: Extract<keyof T, string>;
}
class FormField<T extends FormFields> {
public fieldNameA: string;
public fieldNameB: string;
constructor(options: FormFieldOptions<T>) {
// Does not work because fieldNameA is of type "symbol | number | string" (expected)
this.fieldNameA = options.fieldNameA;
// Does work because fieldNameB is ensured to be a string (expected)
this.fieldNameB = options.fieldNameB;
}
} What I would have expected:
|
Please note: my older comment on this issue is incorrect - |
Is this the same issue ?
|
@amoscatelli No, the issue there is that conditional types ignore the constraints on type parameters when checking assignability, so |
Knock knock three years later 😄 What is the update, if any, on this? // only extract those types from keyof T which make sense with the '>' operator
function isAGreaterThanB <T>(a: T, b: T, compareOnProperty: Extract<keyof T, string | Date | number>) {
return a[compareOnProperty] > b[compareOnProperty];
} (Obviously I understand IntelliSense can't "figure it out" with just this function definition only, but as soon as it is provided with variables that carry a concrete type, it seems obvious, see my Full Playground example.) |
@princefishthrower Your issue is not related to the original issue. I think you might have misunderstood the usage of the keyword Taking back the interface interface ISomething {
foo: string;
bar: Date;
baz: number;
qux: () => void;
quux: { foo: string; };
corge: symbol;
}
type Keys = keyof ISomething; // 'foo' | 'bar' | 'baz' | 'qux' | 'quux' | 'corge';
type ExtractOfKeys = Extract<Keys, string | Date | number>; // 'foo' | 'bar' | 'baz' | 'qux' | 'quux' | 'corge'; Since the keys of My guess is you want only the keys foo, bar or baz, since they map to type FieldOfType<Type, ValueType> = { [K in keyof Type]: Type[K] extends ValueType ? K : never }[keyof Type];
function isAGgreaterThanB<T>(a: T, b: T, compareOnProperty: FieldOfType<T, string | Date | number>) {
return a[compareOnProperty] > b[compareOnProperty];
}
type FieldsOfType = FieldOfType<ISomething, string | Date | number>; // 'foo' | 'bar' | 'baz' Here's a Playground Link if you want to play with it. EDIT: The keys map to ordered types instead of are. |
We're very unequipped to deal with this sort of code. The core question being posed this code is, in essence, does any possible instantiation of That's sort of an easy question when the constraint is a simple object type like type WithoutFooGeneric<P extends Partial<Record<"foo" | "bar", string>>> = Omit2<P, "foo">; This should be an error, since writing type A = WithoutFooGeneric<Record<"bar", string>> violates the constraint of But how is this error even found? It's not through instantiation of the constraint; that won't work - that fails to catch the error here // k: "foo" | "bar"
type K = Partial<Record<"foo" | "bar", string>>; Given an arbitrary constraint So TL;DR this isn't the kind of thing someone can just put up a bugfix for - it implies a very large new kind of reasoning to be able to fix beyond the specific case presented here (aside: fixing only specific cases usually makes everything much worse later). |
TypeScript Version: 2.9.1, 3.0.0-dev.20180601
Search Terms: keyof 2.9 generics extract extends string number symbol
Code
Expected behavior:
Omit
should pass"foo"
as valid type for keyof because generic type extends a type that has this string key.Actual behavior:
Error:
Type '"foo"' does not satisfy the constraint 'Extract<keyof P, string>'.
Playground Link: Link
The text was updated successfully, but these errors were encountered: