-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
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
Function-type props broken in TypeScript #9357
Comments
I tried adding the test case to the project and couldn't reproduce: Vue.extend({
props: {
isValid: {
type: Function,
default: () => true,
}
},
methods: {
useFooFn(): void {
const bar = this.isValid()
alert(bar)
}
}
}); |
@posva Are you using the same TypeScript setup and seeing no compile errors? |
no, I'm using the one we have in the repo |
Can you try with the setup I posted? |
Found a clue: I just downgraded // for Function-type props with a default like `() => false`, `(arg: number) => false`, etc.:
// => TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'boolean | Function' has no compatible call signatures.
// (same error occurs with any return value)
function foo(barEl: HTMLElement) { /* ... */ }
foo(this.$el);
// => TS2345: Argument of type 'Element' is not assignable to parameter of type 'HTMLElement'.
const bar = this.$el.innerText;
// => TS2339: Property 'innerText' does not exist on type 'Element'. Seems that:
|
Reverting #8537, specifically this change: diff --git a/types/options.d.ts b/types/options.d.ts
index cc58affe6a..25eb8a0fdf 100644
--- a/types/options.d.ts
+++ b/types/options.d.ts
@@ -133,7 +133,7 @@ export type PropValidator<T> = PropOptions<T> | Prop<T> | Prop<T>[];
export interface PropOptions<T=any> {
type?: Prop<T> | Prop<T>[];
required?: boolean;
- default?: T | null | undefined | (() => object);
+ default?: T | null | undefined | (() => T | null | undefined);
validator?(value: T): boolean;
} ...fixes the |
And reverting #8809, specifically this change: diff --git a/types/vue.d.ts b/types/vue.d.ts
index 44a892ead3..3832f2c9e4 100644
--- a/types/vue.d.ts
+++ b/types/vue.d.ts
@@ -21,7 +21,7 @@ export interface CreateElement {
}
export interface Vue {
- readonly $el: HTMLElement;
+ readonly $el: Element;
readonly $options: ComponentOptions<Vue>;
readonly $parent: Vue;
readonly $root: Vue; ...fixes the |
I'll see if I can write up a PR for a fix without resurfacing the original issues those PRs were trying to solve. |
Aaaaand I've realized over the past few days that I am not good enough with TypeScript to figure out how to do this. Where...
...in order to get a prop definition such as this: // ...
props: {
isValid: {
type: Function,
default: () => true,
}
},
// ... ...to yield a type of: this.isValid //=> Type: () => boolean ...instead of: this.isValid //=> Type: boolean | () => boolean You'd have to edit the export interface PropOptions<T=any> {
type?: Prop<T> | Prop<T>[];
required?: boolean;
// default?: T | null | undefined | (() => T | null | undefined);
// I guess...?
default?: Function extends T ? (T | null | undefined) : (T | null | undefined | (() => T | null | undefined));
validator?(value: T): boolean;
} Unfortunately, that example doesn't work, and the types of other properties on I believe, currently, a Function-type prop is a unique case. It is (correct me if I'm wrong), the only prop type that does not have the option of a default "factory" function: props: {
fnProp1: {
type: Function,
default: () => false, // type of this.fnProp1 should be `() => boolean`
},
fnProp2: {
type: Function,
default: () => (() => false), // type of this.fnProp2 should be `() => (() => boolean)`
},
boolProp1: {
type: Boolean,
default: false, // type of this.boolProp1 should be `boolean`
},
boolProp2: {
type: Boolean,
default: () => false, // type of this.boolProp2 should STILL be `boolean`
},
strProp1: {
type: String,
default: 'hi', // type of this.strProp1 should be `string`
},
strProp2: {
type: String,
default: () => 'hi', // type of this.strProp2 should STILL be `string`
},
// etc.
}, |
Furthermore, if you want to return an object from the default, it completely skips the function type altogether: // ...
props: {
returnsAnObject: {
type: Function,
default: () => ({}),
}
},
// ...
// Type SHOULD be `Function`, or `() => {}`, but...
this.returnsAnObject; //=> Type: {}
// ...which is not even the [broken] union `{} | () => {}` type like the other cases
this.returnsAnObject();
// Cannot invoke an expression whose type lacks a call signature.
// Type '{}' has no compatible call signatures.
// ... |
I'd rather not keep bumping this unnecessarily, since it's mostly an echo chamber at the moment, but this |
if you annotate with the const Example = Vue.extend({
template: `
<button @click="doSomethingWithFoo()">
<slot></slot>
</button>
`,
props: {
// original issue
fooFn: {
type: Function as PropType<()=>string>,
default: () => { return 'hey this is the default return value'; },
},
returnsAnObject: {
type: Function as PropType<()=>object>,
default: () => ({}),
}
},
methods: {
doSomethingWithFoo(): void {
const obj = this.returnsAnObject(); //obj is object
const bar = this.fooFn(); // bar is string
alert(bar);
},
},
}); there's an PR vuejs/v2.vuejs.org#2068 to update docs |
Is this issue back on TypeScript 3.6? The following compiles fine on TS 3.5.3 and fails on the latest TS 3.6.3. Vue: 2.6.10
Removing Put a repro here: https://github.com/romansp/vue-typescript-prop-function-default. May be related to #10455. |
@romansp I'm fairly confident that hasn't worked without annotation since Vue 2.5.17. Annotating with |
@kjleitz I'm sure that it does work on TS 3.5.3 and Vue 2.6.10. You can try cloning my repro https://github.com/romansp/vue-typescript-prop-function-default. I just pushed |
@romansp Ah, I see, you're not using the same Vue v2.6.10 & TS v3.5.3 must be one of those special combinations that don't error for function props 🤷♂ But even in that branch, the "working" case loses type info from |
This is still broken, even with 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;
},
},
}); I submitted a fix for this in #11223. |
Version
2.5.22
Reproduction link
https://jsfiddle.net/keegan_openbay/gehkx7pf/10/
https://jsfiddle.net/keegan_openbay/018rs3ae/11/
(More explanation in the fiddle, but keep in mind that JSFiddle doesn't show TS errors)
Steps to reproduce
Function
, and with a default function that returns some value; e.g.,What is expected?
What is actually happening?
Vue version: 2.5.22
TypeScript version: 3.0.3
tsconfig.json:
The text was updated successfully, but these errors were encountered: