Skip to content

Change in behavior around keyof any inference #29765

Closed

Description

@mike-north

TypeScript Version: 3.4.0-dev.20190202

Search Terms: any, array, argument

Code

function getProps<T, K extends keyof T>(obj: T, list: K[]): Pick<T, K> {
    return {} as any;
}

const myAny: any = {};


// TS 3.2.2 - getProps returns Pick<any, "foo" | "bar">
// TS 3.4   - getProps returns Pick<any, "foo" | "bar">
const o1 = getProps(myAny, ['foo', 'bar']);

// TS 3.2.2 - getProps returns Pick<any, "foo" | "bar">
// TS 3.4   - getProps returns Pick<any, string>
   // └ 🚨 Type 'Pick<any, string>' is missing the following properties
   //   from type '{ foo: any; bar: any; }': foo, bar [2739]
const o2: { foo: any; bar: any } = getProps(myAny, ['foo', 'bar']);

Expected behavior:

I expect o2 above to type-check successfully in 3.4

Actual behavior:

Playground Link: NOTE: does not demonstrate the reported behavior, since it's only reproducible in recent 3.4 nightly builds

https://www.typescriptlang.org/play/index.html#src=function%20getProps%3CT%2C%20K%20extends%20keyof%20T%3E(obj%3A%20T%2C%20list%3A%20K%5B%5D)%3A%20Pick%3CT%2C%20K%3E%20%7B%0D%0A%20%20%20%20return%20%7B%7D%20as%20any%3B%0D%0A%7D%0D%0A%0D%0Aconst%20myAny%3A%20any%20%3D%20%7B%7D%3B%0D%0A%0D%0A%2F%2F%20TS%203.2.2%20-%20getProps%20returns%20Pick%3Cany%2C%20%22foo%22%20%7C%20%22bar%22%3E%0D%0A%2F%2F%20TS%203.4%20%20%20-%20getProps%20returns%20Pick%3Cany%2C%20string%3E%0D%0Aconst%20o2%3A%20%7B%20foo%3A%20any%3B%20bar%3A%20any%20%7D%20%3D%20getProps(myAny%2C%20%5B'foo'%2C%20'bar'%5D)%3B%0D%0A%0D%0A%2F%2F%20TS%203.2.2%20-%20getProps%20returns%20Pick%3Cany%2C%20%22foo%22%20%7C%20%22bar%22%3E%0D%0A%2F%2F%20TS%203.4%20%20%20-%20getProps%20returns%20Pick%3Cany%2C%20%22foo%22%20%7C%20%22bar%22%3E%0D%0Aconst%20o3%20%3D%20getProps(myAny%2C%20%5B'foo'%2C%20'bar'%5D)%3B%0D%0A

Related Issues: #29698 #25759

Activity

  1. ahejlsberg commented on Feb 6, 2019

    @ahejlsberg
    Member

    Looks like this is an effect of #29478. Previously we'd make no inferences from the return type in the second example, but now we infer from { foo: any; bar: any } to Pick<T, K>. This produces an inference for K, but not for T because Pick<T, K> isn't a homomorphic mapped type (it's partially homomorphic in that it only maps a subset of the properties). Because we have no candidates for T, we end up with an inference of {} from the return type, which then causes us to reduce our inference for K to never. We then proceed with this rather useless contextual type which ends up making matters worse rather than better.

    Looks like we need to do better when inferring to Pick<T, K>. I will see what we can do.

  2. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions