Home > Back-end >  typescript object type with generic result syntax error
typescript object type with generic result syntax error

Time:11-30

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:

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),
};

Playground Link

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;
};
  • Related