TypeScript部分接口对象

Aar*_*all 12 typescript reactjs

在React中,Component定义如下所示:

class Component<S> {
    state:S;
    setState(state:S):void;
}
Run Code Online (Sandbox Code Playgroud)

你定义一个这样的组件:

interface MyState {
    name: string;
    age: number;
}
class MyComponent extends Component<MyState> { }
Run Code Online (Sandbox Code Playgroud)

现在的问题是,在React API setState中应该使用部分状态对象调用,表示要更新的属性,如下所示:

setState({name: "Aaron"});
Run Code Online (Sandbox Code Playgroud)

请注意,age未声明.我遇到的问题是TypeScript不允许这样做,它给出了一个赋值错误Property 'age' is missing.根据我的理解,这个react.d.ts定义在这个意义上是错误的.但是有解决方案吗?

我试过这个:

setState({name: "Aaron"} as MyState);
Run Code Online (Sandbox Code Playgroud)

但是这会产生相同的错误,即使它在Playground中工作而不会出错.为什么它在游乐场有效?有任何想法吗?

Mat*_*ens 17

当前TypeScript中仍然缺少"部分类型",请参阅TypeScript问题#4889以及此相关问题.我担心还不能正确地进行这种类型检查.

可能会将MyState界面的所有字段标记为可选(通过添加?修饰符),但这反过来会削弱类似检查Component.state(如果您希望设置所有字段).

编辑(2016年12月): TypeScript 2.1引入了映射类型,支持使用!来描述部分类型Partial<T>!现在,您可以使用以下类型定义Component:

class Component<S> {
    state: S;
    setState(state: Partial<S>) : void;
}
Run Code Online (Sandbox Code Playgroud)


Spi*_*ike 5

react.d.ts定义的确是错误的,不能固定到部分类型的支持。

问题是它setState需要一个部分状态,这是与正常状态不同的类型。您可以通过手动指定两种类型来解决此问题:

interface MyState {
    name: string;
    age: number;
}

interface PartialMyState {
    name?: string;
    age?: number;
}
Run Code Online (Sandbox Code Playgroud)

并手动声明MyComponent而不扩展提供的 ReactComponent类:

class MyComponent {
    state: MyState;
    setState(state:PartialMyState): void;
    //...
}
Run Code Online (Sandbox Code Playgroud)

这意味着您必须为Component代码中的每个子类复制这些函数定义。您可以通过定义Component由附加类型的部分状态概括的正确类来避免这种情况:

class CorrectComponent<S,P> { // generalized over both state and partial state
    state:S;
    setState(state:P):void;
    //...
}

class MyComponent extends CorrectComponent<MyState,PartialMyState> { }
Run Code Online (Sandbox Code Playgroud)

您仍然需要为您拥有的每个状态类型编写一个部分版本。


或者,您可以setState通过将其参数的类型更改为Object.