question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Wrong keyof behaviour for generic with extends types in 2.9

See original GitHub issue

TypeScript Version: 2.9.1, 3.0.0-dev.20180601

Search Terms: keyof 2.9 generics extract extends string number symbol

Code

type StringKeyof<T> = Extract<keyof T, string>;

type Omit<T, K extends StringKeyof<T>> = any;

type WithoutFoo = Omit<{ foo: string }, "foo">; // ok

type WithoutFooGeneric<P extends { foo: string }> = Omit<P, "foo">; // Error: Type '"foo"' does not satisfy the constraint 'Extract<keyof P, string>'.

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

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:4
  • Comments:10 (3 by maintainers)

github_iconTop GitHub Comments

6reactions
carlvincentldcommented, Mar 14, 2022

@princefishthrower Your issue is not related to the original issue. I think you might have misunderstood the usage of the keyword Extract or keyof T.

Taking back the interface ISomething with slight alteration to the names:

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 ISomething are all strings, Extract returns the full list of keys.

My guess is you want only the keys foo, bar or baz, since they map to are of ordered types. Instead of Extract, you might be looking to use the following “FieldOfType” type:

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.

1reaction
jack-williamscommented, Aug 20, 2019

@amoscatelli No, the issue there is that conditional types ignore the constraints on type parameters when checking assignability, so T[K] extends string ? K : never does not get simplified to K.

Read more comments on GitHub >

github_iconTop Results From Across the Web

TypeScript Wrong typechecking when remapping keys with ...
We're trying to use conditional types to filter a generic type related to keyof a generic type, and the compiler cannot figure out...
Read more >
Documentation - Generics - TypeScript
This allows us to traffic that type information in one side of the function and out the other. We say that this version...
Read more >
Generic and keyof - Learn TypeScript - Educative.io
You can use extends to extend a generic type to another type if you want the generic type to be a subset of...
Read more >
TypeScript Types Deep Dive 3 - Generics and Advanced Types
It includes: * generics * how to DRY your types with advanced types : index access, keyof, typeof, Next part will include: mapped...
Read more >
TypeScript — Confusing Concepts and Usage | by E.Y. | Medium
Sometimes we need to type assert a generic value into a literal type. ... Generic Type using extends , such as <T, K...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found