【问题标题】:TypeScript partial interface objectTypeScript 部分接口对象
【发布时间】:2016-08-06 15:06:07
【问题描述】:

在 React 中,Component definition 看起来像这样:

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

然后你定义一个这样的组件:

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

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

setState({name: "Aaron"});

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

我试过了:

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

但这给出了同样的错误,即使它works in the Playground 没有给出错误。为什么它在操场上有效?有什么想法吗?

【问题讨论】:

  • 我以某种方式设法让部分类型与Object.assign 一起使用(完全使用类型检查,无需创建带有可选成员的接口声明),但我仍然不确定如何。相同的代码在一个项目中有效,但在另一个项目中无效。一旦我弄清楚了,我会发布更新。

标签: reactjs typescript


【解决方案1】:

目前 TypeScript 中仍然缺少“部分类型”,请参阅 TypeScript issue #4889this related question。恐怕还不能正确地进行这种类型检查。

可能MyState 接口的所有字段标记为可选(通过添加? 修饰符)而侥幸,但这反过来会削弱Component.state 之类的类型检查(您希望设置 所有 字段的位置)。

编辑(2016 年 12 月): TypeScript 2.1 引入了mapped types,它支持使用Partial&lt;T&gt; 描述partial types!现在您可以为Component 使用以下类型定义:

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

【讨论】:

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

react.d.ts 的定义确实是错误的,在支持Partial Types 之前无法修复。

问题在于setState 采用部分状态,与正常状态不同。您可以通过手动指定这两种类型来解决此问题:

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

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

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

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 来使 setState 成为非类型安全的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-30
    • 1970-01-01
    • 2014-09-03
    • 2012-11-04
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 2019-11-26
    相关资源
    最近更新 更多