Skip to content

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

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

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

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

No branches or pull requests

4 participants