i get syntax error when when trying to assign value as the result of generic Merge
into object type(type of key-value)
type Merge<a,b> = any
type test<P, S= any, K= any> = {
jsx1?: (state: Merge<K, S>, props: P, nextJsx?) => JSX.Element; //ok
jsx2?: ({state: S, props: P, nextJsx}) => JSX.Element; // ok
jsx3?: ({ state: Merge<K, S>, props: P, nextJsx }) => JSX.Element; // error - why?
// ^ webstorm: ", expected" ^ vscode: ';' expected.(1005)
};
IDE: webstorm
why is that considered syntax error? how can I assign jsx3->state
to type Merge
typescript 4.4.4.
in vs code: very similar result but the error is ';'expected.ts(1005)
on the arrow function. same error in ts playground:
CodePudding user response:
In the signature ({state: S, props: P, nextJsx}) => JSX.Element
, S
and P
are not types, they are identifiers. In this context, the colon :
does not mean a type annotation, it means rebinding the name of a property, like in the following example:
const obj = {foo: 23};
// bar is not a type annotation here
const {foo: bar} = obj;
// 23
console.log(bar);
I'm not sure what the usefulness of parameter rebinding would be in a type declaration, but for better or worse, that's what it means. So the error is because Merge<K, S>
is not a valid identifier for rebinding; but in fact both your jsx2
and your jsx3
declarations have problems, it's just that you didn't get an error for the other one.
The solution is to put the types in a place where, contextually, they actually are types; i.e. in the parameter's type annotation.
type Test<P, S=any, K=any> = {
jsx1?: (state: Merge<K, S>, props: P, nextJsx?) => JSX.Element;
jsx2?: (params: {state: S, props: P, nextJsx}) => JSX.Element;
jsx3?: (params: {state: Merge<K, S>, props: P, nextJsx}) => JSX.Element;
}
Note the parameter is a single object named params
, and its type now occurs in a type annotation context so it is not parsed as rebinding identifiers. Also, although there is a single named parameter params
in the type declaration, it is still perfectly possible to do parameter destructuring (and rebinding, if you want to) when you actually implement these functions:
const test: Test<number, number, number> = {
jsx2: ({state, props, nextJsx}) => console.log(state, props, nextJsx),
jsx3: ({state, props, nextJsx}) => console.log(state, props, nextJsx),
};
CodePudding user response:
You are destructuring your objects with different names in jsx2
and jsx3
, instead of typing them. And in case of jsx3
this is invalid syntax. What you want to do, is to properly type function argument:
type Merge<A,B> = any;
type JSX2Args<P, S> = {
state: S,
props: P,
nextJsx: unknown
}
type JSX3Args<P, S, K> = {
state: Merge<K, S>,
props: P,
nextJsx: unknown
}
type test<P, S= any, K= any> = {
jsx1?: (state: Merge<K, S>, props: P, nextJsx?) => JSX.Element;
jsx2?: (arg: JSX2Args<P, S>) => JSX.Element;
jsx3?: ({ state, props, nextJsx }: JSX3Args<P, S, K>) => JSX.Element;
};