TypeScript 部分接口对象

IT技术 reactjs typescript
2021-03-31 14:28:47

在 React 中,组件定义如下所示:

class Component<S> {
    state:S;
    setState(state:S):void;
}

你定义一个这样的组件:

interface MyState {
    name: string;
    age: number;
}
class MyComponent extends Component<MyState> { }

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

setState({name: "Aaron"});

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

我试过这个:

setState({name: "Aaron"} as MyState);

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

2个回答

当前 TypeScript 中仍然缺少“部分类型”,请参阅TypeScript 问题 #4889以及此相关问题恐怕现在还不可能正确地进行这种类型检查。

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

编辑(2016年12月):打字稿2.1引入映射类型,它支持描述局部类型使用Partial<T>现在您可以将以下类型定义用于Component

class Component<S> {
    state: S;
    setState(state: Partial<S>) : void;
}
@Aaron 该示例有效,因为它as MyState充当类型检查器的覆盖。不过,我不知道相同的代码在您的本地构建中会如何失败......
2021-05-24 14:28:47
@MattiasBuelens 这似乎与可选属性有关。看这里。这里有什么区别?
2021-05-25 14:28:47
仅举一个给定解决方法的示例,在您的情况下,您的界面将是: interface MyState { name?: string; age?: number; }
2021-06-04 14:28:47
@MattiasBuelens 我已经接受了这个答案,但是我仍然很困惑为什么interface S {a: string; b: string};使用let s:S = {a:"hi"} as S;,但是如果我将其设为a可选,例如interface S { a?: string; b: string},那么它会在b缺少的赋值/断言中给出错误
2021-06-17 14:28:47
谢谢。事实上,我避免将所有字段标记为可选,因为它不是真的……知道为什么我的 Playground 示例有效吗?好像不应该?
2021-06-20 14:28:47

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

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

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

interface PartialMyState {
    name?: string;
    age?: number;
}

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

class MyComponent {
    state: MyState;
    setState(state:PartialMyState): void;
    //...
}

这意味着您必须为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> { }

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


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