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

fix(types): fix function prop type inference #11223

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from

Conversation

kjleitz
Copy link

@kjleitz kjleitz commented Mar 19, 2020

close #9357

What kind of change does this PR introduce? (check at least one)

  • Bugfix
  • Feature
  • Code style update
  • Refactor
  • Build-related changes
  • Other, please describe:

Does this PR introduce a breaking change? (check one)

  • Yes
  • No

If yes, please describe the impact and migration path for existing applications:

The PR fulfills these requirements:

If adding a new feature, the PR's description includes:

  • A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

Other information:

Before this change:

const ComponentWithFunctionProps = Vue.extend({
  props: {
    functionProp: {
      type: Function,
      default: () => true,
    },
    functionPropWithBooleanReturnType: {
      type: Function as PropType<() => boolean>,
      default: () => true,
    },
    booleanProp: {
      type: Boolean,
      default: true,
    },
    booleanPropWithFunctionDefault: {
      type: Boolean,
      default: () => true,
    },
  },
  methods: {
    test(): void {
      // ERROR!
      // (property) functionProp: boolean | Function
      // -------------------------------------------
      // This expression is not callable.
      //   No constituent of type 'boolean | Function' is callable.ts(2349)
      this.functionProp();

      // ERROR!
      // (property) functionPropWithBooleanReturnType: boolean | (() => boolean)
      // -----------------------------------------------------------------------
      // This expression is not callable.
      //   Not all constituents of type 'boolean | (() => boolean)' are callable.
      //     Type 'false' has no call signatures.ts(2349)
      this.functionPropWithBooleanReturnType();

      // const foo: boolean
      const foo = this.booleanProp;

      // const bar: boolean
      const bar = this.booleanPropWithFunctionDefault;
    },
  },
});

After this change:

const ComponentWithFunctionProps = Vue.extend({
  props: {
    functionProp: {
      type: Function,
      default: () => true,
    },
    functionPropWithBooleanReturnType: {
      type: Function as PropType<() => boolean>,
      default: () => true,
    },
    booleanProp: {
      type: Boolean,
      default: true,
    },
    booleanPropWithFunctionDefault: {
      type: Boolean,
      default: () => true,
    },
  },
  methods: {
    test(): void {
      // (property) functionProp: Function
      this.functionProp();

      // (property) functionPropWithBooleanReturnType: () => boolean
      this.functionPropWithBooleanReturnType();

      // const foo: boolean
      const foo = this.booleanProp;

      // const bar: boolean
      const bar = this.booleanPropWithFunctionDefault;
    },
  },
});

@kjleitz kjleitz changed the title fix(types): fix function prop type inference, fix #9357 fix(types): fix function prop type inference (fix #9357) Mar 20, 2020
@kjleitz
Copy link
Author

kjleitz commented Mar 20, 2020

@ktsn this might be up your alley!

@@ -154,6 +154,45 @@ const FunctionalScopedSlotsComponent = Vue.extend({
}
});

declare function assertBoolean<A>(value: string extends A ? never : (A extends boolean ? A : never)): true;
Copy link
Author

@kjleitz kjleitz Mar 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To explain a little: calling assertBoolean(value) will only compile if value is precisely boolean, and not if value is boolean | AnotherType, nor if value is any (the latter is why ...lue: string extends A ? nev... is there—it's just a way to throw if value is any).

Comment on lines +188 to +189
this.functionProp(); // callable (good)
assertBoolean(this.functionPropWithBooleanReturnType())
Copy link
Author

@kjleitz kjleitz Mar 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference...

Before the change, these lines were failing with:

this.functionProp();

(property) functionProp: boolean | Function
This expression is not callable.
No constituent of type 'boolean | Function' is callable. ts(2349)

assertBoolean(this.functionPropWithBooleanReturnType());

(property) functionPropWithBooleanReturnType: boolean | (() => boolean)
This expression is not callable.
Not all constituents of type 'boolean | (() => boolean)' are callable.
Type 'false' has no call signatures. ts(2349)

@kjleitz
Copy link
Author

kjleitz commented Mar 25, 2020

Also related: microsoft/TypeScript#17574 and #9873

@kjleitz
Copy link
Author

kjleitz commented Mar 27, 2020

Note: If it helps with confidence, I've tested that this change works & compiles in a project with 154 different .vue SFC files (consisting of a little over 23,000 lines of code), all using TypeScript.

@medinab
Copy link

medinab commented Mar 27, 2020

I've been looking for a solution for some time now, thanks!

@kjleitz
Copy link
Author

kjleitz commented Jul 20, 2020

Can anyone look at this? I'd really appreciate it!

@doyaaaaaken
Copy link

doyaaaaaken commented Sep 24, 2020

Hi, is there any update on this? I'd be happy this PR was merged.

@kjleitz
Copy link
Author

kjleitz commented Oct 1, 2020

Can someone look at this? It's been a thorn in our side for a long time.

@kjleitz
Copy link
Author

kjleitz commented Oct 1, 2020

@ktsn ?

@posva posva changed the title fix(types): fix function prop type inference (fix #9357) fix(types): fix function prop type inference Mar 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Function-type props broken in TypeScript
3 participants