Skip to content

Failed function argument type inference inside nested object passed as argument #22715

Closed
@beshanoe

Description

@beshanoe

TypeScript Version: 2.7.1

Search Terms: infer

Code

interface IFooOptions<K extends string> {
  name?: string;
  value?: number;
  allFoos?: {[key in K]?: boolean }
  fn?: (allFoos: {[key in K]: string }) => void;
}

class Bar<T> {
  constructor(foos: {[key in keyof T]: IFooOptions<keyof T> }) {
    // ...
  }
}

const bar = new Bar({
  firstFoo: {
    name: "john",
    value: 3,
    allFoos: { // here allFoos infered
      firstFoo: true,
      nonexist: 'yep'
    }
  },
  secondFoo: {
    name: 'sandra',
    fn: allFoos => { // but here allFoos is any though the type of "fn" is infered correctly
      allFoos.nonexist = 2
    }
  }
});

const myFoo: IFooOptions<'one' | 'two'> = {
  name: 'adas',
  fn: allFoos => { //allFoos is infered right
    allFoos.nonexist = 2
  }
}

Expected behavior:

The allFoos argument inside fn field in the new Bar argument should have a type of

{
  firstFoo: string
  secondFoo: string
}

Actual behavior:

allFoos type is implicit any
Also it repoduces without using a class, just with plain generic function

Playground Link:
https://www.typescriptlang.org/play/index.html#src=interface%20IFooOptions%3CK%20extends%20string%3E%20%7B%0A%20%20name%3F%3A%20string%3B%0A%20%20value%3F%3A%20number%3B%0A%20%20allFoos%3F%3A%20%7B%5Bkey%20in%20K%5D%3F%3A%20boolean%20%7D%0A%20%20fn%3F%3A%20(allFoos%3A%20%7B%5Bkey%20in%20K%5D%3A%20string%20%7D)%20%3D%3E%20void%3B%0A%7D%0A%0Aclass%20Bar%3CT%3E%20%7B%0A%20%20constructor(foos%3A%20%7B%5Bkey%20in%20keyof%20T%5D%3A%20IFooOptions%3Ckeyof%20T%3E%20%7D)%20%7B%0A%20%20%20%20%2F%2F%20...%0A%20%20%7D%0A%7D%0A%0Aconst%20bar%20%3D%20new%20Bar(%7B%0A%20%20firstFoo%3A%20%7B%0A%20%20%20%20name%3A%20%22john%22%2C%0A%20%20%20%20value%3A%203%2C%0A%20%20%20%20allFoos%3A%20%7B%20%2F%2F%20here%20allFoos%20infered%0A%20%20%20%20%20%20firstFoo%3A%20true%2C%0A%20%20%20%20%20%20nonexist%3A%20'yep'%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20secondFoo%3A%20%7B%0A%20%20%20%20name%3A%20'sandra'%2C%0A%20%20%20%20fn%3A%20allFoos%20%3D%3E%20%7B%20%2F%2F%20but%20here%20allFoos%20is%20any%20though%20the%20type%20of%20%22fn%22%20is%20infered%20correctly%0A%20%20%20%20%20%20allFoos.nonexist%20%3D%202%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D)%3B%0A%0Aconst%20myFoo%3A%20IFooOptions%3C'one'%20%7C%20'two'%3E%20%3D%20%7B%0A%20%20name%3A%20'adas'%2C%0A%20%20fn%3A%20allFoos%20%3D%3E%20%7B%20%2F%2FallFoos%20is%20infered%20right%0A%20%20%20%20allFoos.nonexist%20%3D%202%0A%20%20%7D%0A%7D

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions