JSX 节点中的 TypeScript 类型参数

TypeScript type arguments in JSX nodes

有什么方法可以为在 JSX 中呈现的组件指定类型参数吗?

例如,考虑这个组件:

interface SelectorProps<T> {
    selection: T;
    options: T[];
}

class Selector<T> extends React.Component<SelectorProps<T>, {}> {
    // ...
}

如果我尝试在 JSX 中呈现此组件:

<Selector selection="a" options={["a", "b", "c"]} />

我收到这些错误:

TS2322: Type 'string' is not assignable to type 'T'.

TS2322: Type 'string[]' is not assignable to type 'T[]'. Type 'string' is not assignable to type 'T'.

我希望 T 被推断为 string 或者以某种方式在 <Selector> 中指定 T=string。有解决办法吗?

我发现的唯一解决方法是扩展组件以消除所有类型参数:

class StringSelector extends Selector<string> { }

试试这个。您的接口应该明确声明它期望的值类型。这就是使用打字稿的全部意义所在。如果你真的知道会发生什么,你不应该推断任何东西。

interface SelectorProps {
    selection: string | number; // This means selection can take in either a string or a number
    options: string[] | number[];
}

class Selector extends React.Component<SelectorProps, {}> {
    // ...
}

我已经在我公司创建的组件中使用泛型,但我设法做到的方式并不漂亮。

GenericComponent.tsx:

import * as React from "react";

interface IGenericComponentProps<T, S> {
    propT: T;
    propS: S;
}

interface IGenericComponentState<T, S> {}

export class GenericComponent<T, S> extends React.Component<
    IGenericComponentProps<T, S>,
    IGenericComponentState<T, S>
    > {
    public render(): JSX.Element {
        return (
            <div>Generic component!</div>
        );
    }

}

export default GenericComponent;

GenericComponentImplementation.tsx:

import * as React from "react";

// This is the ugly part
import GenericComponentBase from "./GenericComponent";
// This is where you get to define the generic type arguments
interface StringAndNumberComponentBase { new (): GenericComponentBase<string, number>; };
const StringAndNumberComponent = GenericComponentBase as StringAndNumberComponentBase ;

export default (): JSX.Element => {
    return (
        <StringAndNumberComponent
            propT="test"
            propS={2}
            />
    );
};

我想我当时从这个 github 问题中得到了这些信息: https://github.com/Microsoft/TypeScript/issues/3960

interface FooProps<T> { foo: T; }
class Foo<T> extends React.Component<FooProps<T>, any> {
  render() {
    return <div>{ JSON.stringify(this.props.foo) }</div>;
  }
}
type FooBar = new () => Foo<{bar: string}>;
const FooBar = Foo as FooBar;

class FooBarContainer extends React.Component<any, any> {
  render() {
    return <FooBar foo={{bar: 'works'}} />;
  }
}

FooBarContainer<FooBar foo={{bar: 'works'}} /> 应该呈现:<div>{"bar":"works"}</div>

现在支持 https://github.com/Microsoft/TypeScript/issues/6395 中描述的通用 JSX 元素 - 从 TypeScript 2.9 开始。

您现在应该可以使用:

 <Selector<string> selection="a" options={["a", "b", "c"]} />

另请参阅:http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html