microsoft / microsoft/TypeScript

ThisType would disturb Generics' inferring type when assign an expression to a type variable

Open
#39,848 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Needs Investigation
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

TypeScript Version: 3.9.2, and it does exist in 'Nightly' version, too.

Search Terms: ThisType, Generics, Inferring problem

Code

type customFunc = (...args: any) => any

declare function SimpleVue<
  D,
  C extends { [K in string]: customFunc },
  M = { [K in string]: customFunc },
  CC = { [K in keyof C]: ReturnType<C[K]> },
  ReturnedD = D extends customFunc ? ReturnType<D> : never,
>(option: {
  data: D,
  methods: M,
  computed: C
} & ThisType<M & ReturnedD & CC>): ReturnedD

const instance = SimpleVue({
  data() {
    return {
      firstname: 'Type',
      lastname: 'Challenges',
      amount: 10,
    }
  },
  computed: {
    fullname() {
      return this.firstname + ' ' + this.lastname
    }
  },
  methods: {
    hi() {
      alert(this.fullname.toLowerCase())
    }
  }
});

Expected behavior:

We expect ReturnedD = D extends customFunc ? ReturnType<D> : never infers ReturnedD to ReturnType<D> at runtime since D fits the shape of customFunc:

() => {
    firstname: string;
    lastname: string;
    amount: number;
}

And the code should show no error in TypeScript environment.

Actual behavior:

The actual behavior is that ReturnedD is inferred to never type since D extends customFunc here is false at runtime.

You can also check it with the returned type of instance as well.

Playground Link:

Check out the link here.

Personal speculation:

If you look at the demo above, you can do following steps to remove the error hint and confirm ReturnedD's correction:

  1. Remove ReturnedD from ThisType<M & ReturnedD & CC>;
  2. Save the file;
  3. Error disappeared on this.firstname, etc;
  4. The returned type of instance inferred from TypeScript is as expected and would not be never;

I also reproduced it with TypeScript playground.

We can confirm that:

  1. ReturnedD runs well in inferring type at runtime;
  2. The wrong type may be caused by some mechanism inside ThisType;

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the TypeScript 3.9.2 playground reproduction and compare inference with and without ReturnedD in ThisType<M & ReturnedD & CC>. Trace how ThisType affects the conditional type D extends customFunc ? ReturnType : never. Done means the example reports no errors and instance no longer infers ReturnedD as never.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.