Skip to content
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

Type argument inference for Extract<key of T, string> too broad (binds all possible keys) #25065

Closed
7sempra opened this issue Jun 19, 2018 · 1 comment
Assignees
Labels
Bug A bug in TypeScript

Comments

@7sempra
Copy link

7sempra commented Jun 19, 2018

TypeScript Version: 2.9.2

Search Terms: keyof generic interference

In the example below, the calls to getPropertyX(obj, 'first') should bind the type of K as 'first'. However, when the definition of K involves Extract, the inferred binding is 'first' | 'second' instead (i.e. all possible keys).

Apropos due to the keyof changes in 2.9.

Code

// Declaration uses keyof -- no problems
function getProperty<T, K extends keyof T>(obj: T, key: K) {
    return obj[key];
}

// Type argument uses bare keyof, function argument uses Extract (doesn't work)
function getProperty2<T, K extends keyof T>(obj: T, key: Extract<K, string>): T[K] {
    return obj[key];
}

// Type argument uses Extract (doesn't work)
function getProperty3<T, K extends Extract<keyof T, string>>(obj: T, key: K): T[K] {
    return obj[key];
}


interface StrNumPair {
    first: string,
    second: number,
}
const obj: StrNumPair = {} as any;

let prop: string;

// Works
prop = getProperty(obj, 'first');

// Doesn't work -- string | number is not assignable to string
prop = getProperty2(obj, 'first');

// Doesn't work -- string | number is not assignable to string
prop = getProperty3(obj, 'first');

// Explicit generic binding -- works
prop = getProperty2<StrNumPair, 'first'>(obj, 'first');
prop = getProperty3<StrNumPair, 'first'>(obj, 'first');

Expected behavior: K is bound to just the key passed ('first')

Actual behavior: K is bound to all possible keys ('first' | 'second').

Playground Link: http://www.typescriptlang.org/play/#src=%0D%0Afunction%20getProperty%3CT%2C%20K%20extends%20keyof%20T%3E(obj%3A%20T%2C%20key%3A%20K)%20%7B%0D%0A%20%20%20%20return%20obj%5Bkey%5D%3B%0D%0A%7D%0D%0A%0D%0Afunction%20getProperty2%3CT%2C%20K%20extends%20keyof%20T%3E(obj%3A%20T%2C%20key%3A%20Extract%3CK%2C%20string%3E)%3A%20T%5BK%5D%20%7B%0D%0A%20%20%20%20return%20obj%5Bkey%5D%3B%0D%0A%7D%0D%0A%0D%0Afunction%20getProperty3%3CT%2C%20K%20extends%20Extract%3Ckeyof%20T%2C%20string%3E%3E(obj%3A%20T%2C%20key%3A%20K)%3A%20T%5BK%5D%20%7B%0D%0A%20%20%20%20return%20obj%5Bkey%5D%3B%0D%0A%7D%0D%0A%0D%0A%0D%0Ainterface%20StrNumPair%20%7B%0D%0A%20%20%20%20first%3A%20string%2C%0D%0A%20%20%20%20second%3A%20number%2C%0D%0A%7D%0D%0Aconst%20obj%3A%20StrNumPair%20%3D%20%7B%7D%20as%20any%3B%0D%0A%0D%0Alet%20prop%3A%20string%3B%0D%0A%0D%0A%2F%2F%20Works%0D%0Aprop%20%3D%20getProperty(obj%2C%20'first')%3B%0D%0A%0D%0A%2F%2F%20Doesn't%20work%20--%20string%20%7C%20number%20is%20not%20assignable%20to%20string%0D%0Aprop%20%3D%20getProperty2(obj%2C%20'first')%3B%0D%0A%0D%0A%2F%2F%20Doesn't%20work%20--%20string%20%7C%20number%20is%20not%20assignable%20to%20string%0D%0Aprop%20%3D%20getProperty3(obj%2C%20'first')%3B%0D%0A%0D%0A%2F%2F%20Explicit%20generic%20binding%20--%20works%0D%0Aprop%20%3D%20getProperty2%3CStrNumPair%2C%20'first'%3E(obj%2C%20'first')%3B%0D%0Aprop%20%3D%20getProperty3%3CStrNumPair%2C%20'first'%3E(obj%2C%20'first')%3B

Related Issues:

@s-ve
Copy link

s-ve commented Jun 19, 2018

Possibly related to #24560

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants