reactjs - Typescript:通过添加具有特定命名的新字段来动态扩展接口(interface)

标签 reactjs typescript interface react-context openapi-generator

我有一个这样的界面:

interface ProjectCostData {
  purchasePrice: number;
  propertyValue: number;
  recentlyDamaged: boolean;
}

现在我想基于上面的界面动态创建一个这样的界面:

interface ProjectCostDataWithSetters {
  purchasePrice: number;
  setPurchasePrice: Dispatch<SetStateAction<number>>;
  propertyValue: number;
  setPropertyValue: Dispatch<SetStateAction<number>>;
  recentlyDamaged: boolean;
  setRecentlyDamage: Dispatch<SetStateAction<boolean>>;
}

--> 映射第一个接口(interface),并为每个条目 A 添加一个带有键 `set${entryKey}` 的新条目 B 以及可以从条目 A 派生的类型。

这在 TS 中可能吗?

背景:我有一个基于 OpenAPI 的后端,它以 .yaml 文件的形式为我提供 API 结构。我通过生成器传递该文件并接收与 API 对话的接口(interface)和函数。在前端,我使用 react 上下文来构建全局状态。我想根据生成器的输出构建我的全局 react 上下文。

最佳答案

在 typescript 4.0 或更早版本中,这是不可能的。字符串(包括属性名称)要么完全被称为常量(即 "foo"),要么是一组有限可能性的常量之一(即 "foo"| "bar" >),或任何具有任何内容的字符串 (string)。因此您不能根据其他属性名称构造新的属性名称。


但是,Typescript 4.1(当前测试版)的一些功能可能会在 template literal types 中有所帮助。

interface ProjectCostData {
  purchasePrice: number;
  propertyValue: number;
  recentlyDamaged: boolean;
}

// Create a new setter property for each key of an interface
type WithSetters<T extends { [k: string]: any }> = T & {
    [K in keyof T & string as `set_${K}`]: (newValue: T[K]) => void
}

// Testing
declare const obj: WithSetters<ProjectCostData>
obj.purchasePrice // number
obj.set_purchasePrice(123) // (newValue: number) => void

Playground

那个:

[K in keyof T & string as `set_${K}`]

有点时髦。 This PR explains that better than I could.


您甚至可以处理大小写更改:

interface Capitals { a: 'A', b: 'B', c: 'C' /* ... */, p: 'P' }

type Capitalize<T extends string> =
    T extends `${infer First}${infer Rest}`
        ? First extends keyof Capitals
            ? `${Capitals[First]}${Rest}`
            : T
        : T


type SetterName<T extends string> = `set${Capitalize<T>}`

type SetPropName = SetterName<'propName'> // type: "setPropName"

Playground

将所有这些放在一起有点棘手,尤其是在测试版中。但我认为,从理论上讲,所有的部分都是为了实现这种类型转换而存在的。

关于reactjs - Typescript:通过添加具有特定命名的新字段来动态扩展接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64034690/

相关文章:

reactjs - React 中的更新事件 : order?

angular - 从不同的组件调用函数并传递参数

java - 为什么接口(interface)不能是最终的?

c# - 让类实现不同接口(interface)以限制客户端操作时的设计问题

java - 使用 JAVA 访问 MS Outlook

node.js - 当我运行 "expo init my-app"时,我无法使用 expo 构建项目(React Native 和 Node)

javascript - 如何为数组中的每个元素分配随机颜色?

javascript - React Router browserHistory.push 在新标签页中打开链接

typescript - 在编译时获取 Generic 的名称

javascript - 配置 ESLint 以将 .ts 和 .tsx 解析为 Typescript,将 .js 和 .jsx 解析为 Ecmascript