TypeScript 泛型

2023-12-25

我正在努力解决如何使用 TypeScript 强类型化某些功能。

本质上,我有一个函数,它接受 DataProviders 的键/值映射并返回每个数据提供者返回的数据的键/值映射。这是问题的简化版本:

interface DataProvider<TData> {
    getData(): TData;
}

interface DataProviders {
    [name: string]: DataProvider<any>;
}

function getDataFromProviders<TDataProviders extends DataProviders>(
    providers: TDataProviders): any {

    const result = {};

    for (const name of Object.getOwnPropertyNames(providers)) {
        result[name] = providers[name].getData();
    }

    return result;
}

现在getDataFromProviders返回类型为any但我想要它,这样如果像这样调用......

const values = getDataFromProviders({
    ten: { getData: () => 10 },
    greet: { getData: () => 'hi' }
});

...then values将隐式强类型化为:

{
    ten: number;
    greet: string;
}

我想这将涉及返回一个泛型类型,其泛型参数为TDataProviders但我不太明白。

这是我能想到的最好的,但无法编译......

type DataFromDataProvider<TDataProvider extends DataProvider<TData>> = TData;

type DataFromDataProviders<TDataProviders extends DataProviders> = {
    [K in keyof TDataProviders]: DataFromDataProvider<TDataProviders[K]>;
}

我正在努力想出一个DataFromDataProvider无需我传入即可编译的类型TData明确作为第二个参数,我认为我做不到。

任何帮助将不胜感激。


想象一下,您有一个类型将提供程序名称映射到提供程序返回的数据类型。像这样的东西:

interface TValues {
    ten: number;
    greet: string;
}

请注意,您实际上不必定义这个类型,想象它存在,并将其用作泛型参数,命名为TValues,到处:

interface DataProvider<TData> {
    getData(): TData;
}

type DataProviders<TValues> = 
    {[name in keyof TValues]: DataProvider<TValues[name]>};


function getDataFromProviders<TValues>(
    providers: DataProviders<TValues>): TValues {

    const result = {};

    for (const name of Object.getOwnPropertyNames(providers)) {
        result[name] = providers[name].getData();
    }

    return result as TValues;
}


const values = getDataFromProviders({
    ten: { getData: () => 10 },
    greet: { getData: () => 'hi' }
});

神奇地(事实上,使用从映射类型推断 https://www.typescriptlang.org/docs/handbook/advanced-types.html#inference-from-mapped-types正如 @Aris2World 指出的那样),typescript 能够推断出正确的类型:

let n: number = values.ten;
let s: string = values.greet;

update: 正如问题作者所指出的,getDataFromProviders上面的代码并没有真正检查它接收的对象的每个属性是否符合DataProvider界面。

例如,如果getData拼写错误,没有错误,只是将空对象类型推断为返回类型getDataFromProviders(因此,当您尝试访问结果时,您仍然会收到错误)。

const values = getDataFromProviders({ ten: { getDatam: () => 10 } });

//no error, "const values: {}" is inferred for values

有一种方法可以让打字稿更早地检测到这个错误,但代价是增加了复杂性DataProviders类型定义:

type DataProviders<TValues> = 
    {[name in keyof TValues]: DataProvider<TValues[name]>}
   & { [name: string]: DataProvider<{}> };

与 的交集可转位型 https://www.typescriptlang.org/docs/handbook/interfaces.html#indexable-types添加了一个要求,即每个属性DataProviders必须兼容DataProvider<{}>。它使用空对象类型{}作为一般论点DataProvider因为DataProvider具有适用于任何数据类型的良好属性T, DataProvider<T>兼容于DataProvider<{}> - T是返回类型getData(),并且任何类型都与空对象类型兼容{}.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TypeScript 泛型 的相关文章

随机推荐

  • 使文本块只读

    目前我在滚动查看器控件中放置了一个文本块 如何使文本块只读 文本块 http msdn microsoft com en us library system windows controls textblock aspx已经是只读的 它们旨
  • 为什么会出现错误 ORA-00937

    对于每名获得三架以上飞机认证的飞行员 找到 援助和他 或她 所乘坐的飞机的最大航程 认证为 我有四张桌子 FLIGHTS flno varchar 出发地 varchar 目的地 varchar 距离 整数 出发 日期 到达 日期 飞机 a
  • Android httpclient cookie拒绝非法路径属性

    我正在构建一个 Android 应用程序 它使用 httpclient 将数据发布到 WordPress 服务器并检索数据 由于 cookie 中的路径无效 我无法发送发布数据 这是我检索到的日志 Cookie rejected Basic
  • 高效解析大型 JSON 数组的前四个元素

    我在用Jackson从 json 解析 JSONinputStream如下所示 36 100 The 3n 1 problem 56717 0 1000000000 0 6316 0 0 88834 0 45930 0 46527 5209
  • 如何复制图像?

    我想复制image png form folder1 to folder2 怎么做 folder1 image png folder2 Thanks 尝试这样的事情 var fs require fs var inStr fs create
  • PHP包含html页面字符集问题

    使用下面的代码查询 mysql 数据库后 我生成了一个 html 文件 myFile page htm fh fopen myFile w 或 die 无法打开文件 fwrite fh row 文本 fclose fh 在 mysql 数据
  • 如何运行内存中下载的文件? [复制]

    这个问题在这里已经有答案了 可能的重复 使用 C 加载 EXE 文件并从内存中运行它 https stackoverflow com questions 3553875 load an exe file and run it from me
  • 从 C++ 中查找 python 函数参数

    我正在从 C 调用 python 函数 我想知道是否可以确定参数的数量和这些参数的名称 我已阅读链接如何从 C 语言中查找 Python 函数的参数数量 https stackoverflow com questions 1117164 h
  • 如何从最小最大算法中获取实际移动而不是移动值

    我目前正在为国际象棋编写一个带有 alpha beta 剪枝的极小极大算法 从我见过的所有示例中 极小极大算法将返回一个 int 值 该值表示最佳得分或最佳移动所产生的棋盘状态 我的问题是我们如何返回与分数返回值相关的最佳动作 例如 下面的
  • 如何将 TensorFlow (v. 2) Hub 中预训练的 KerasLayer 与 tfrecords 结合起来?

    我有一个包含 23 个类的 tfrecord 每个类有 35 张图像 总共 805 张 我当前的 tfrecord 读取函数是 def read tfrecord serialized example feature description
  • knockoutjs 检查绑定

    我遇到了问题checked绑定 单击复选框不会更新可见状态 尽管 dependentObservable 指示值已更改 这是 HTML 片段
  • 如何使用标记创建范围滑块并更改填充范围的颜色?

    我已经在某种程度上完成了工作 如下所示 如何实现像这样的范围滑块 slidecontainer width 100 Width of the outside container The slider itself slider webkit
  • 如何创建一个包含每个项目复选框的组合框?

    对 tkinter 和 python 相当陌生 我想知道如何实现一个像这样的按钮 单击按钮下拉列表 所以这是一个组合框 列表的每一行都有一个复选框 最后 如果单击复选框 则运行一个函数 或者 甚至更好 一旦不再删除组合框 就运行一个将项目检
  • 使用 Azure AD 客户端凭据授予流程的 Azure Devops Access

    我已成功通过 Azure AD 进行身份验证并收到访问令牌 我已授予 Azure AD App API 访问 Azure DevOps 的权限 我正在使用 RestSharp Http 客户端进行身份验证 var client new Re
  • 无法将 NumPy 数组转换为张量(不支持的对象类型字典)

    我的方法我认为问题是 history model fit generator train generator epochs epochs steps per epoch train steps verbose 1 callbacks che
  • R 的 UTF-8 编码问题

    尝试解析墨西哥参议院的参议院声明 但在网页的 UTF 8 编码方面遇到问题 这个html清晰可见 library rvest Senate lt html http comunicacion senado gob mx index php
  • neo4j中计算节点深度

    我在 Neo4j 中有这个查询 MATCH sentence Sentence r gt n Word WITH n COUNT r AS c RETURN n c 我的图是一个语言数据库 包含单词及其之间的依赖关系 此查询应返回节点深度
  • 指南针仅在部分运行

    当我尝试通过键入以下内容在命令行上获取我的版本时 compass version 我收到以下错误 Errno ENOENT on line 25 of usr lib ruby vendor ruby compass version rb
  • 使用不同的类型和消息重新引发异常,保留现有信息

    我正在编写一个模块 并希望为它可能引发的异常建立一个统一的异常层次结构 例如 从FooError所有的抽象类foo模块的特定例外 这允许模块的用户捕获这些特定的异常并在需要时明确地处理它们 但是模块引发的许多异常是由于其他一些异常而引发的
  • TypeScript 泛型

    我正在努力解决如何使用 TypeScript 强类型化某些功能 本质上 我有一个函数 它接受 DataProviders 的键 值映射并返回每个数据提供者返回的数据的键 值映射 这是问题的简化版本 interface DataProvide