有一种从值生成类型的typeof方法,但它只将值直接转换为类型. 我想使用一个对象的值为另一个对象创建类型信息,如下所示,

type Column = Readonly<{ type: "numeric" | "text"; name: string }>;

type TypeOfColumns<T extends Column[]> = {}; // ...

const columns: Column[] = [
    { type: "numeric", name: "id" },
    { type: "text", name: "firstName" },
];

// If I wrote the following,
type ColumnType = TypeOfColumns<typeof columns>;

// I want the type to be inferred as follows,
type NeedColumnType = { id: number; firstName: string };

我以为我可以通过使用扩展来读取值,但它根本不起作用.

type Column = Readonly<{ type: "numeric" | "text"; name: string }>;

type TypeOfColumn<T extends Column> = {
    [key in T["name"]]: T["type"] extends "numeric" ? number : string;
};

type TypeOfColumns<T extends Column[]> = {
    [key in T[number]["name"]]: TypeOfColumn<T[number]>;
};

const columns: Column[] = [
    { type: "numeric", name: "id" },
    { type: "text", name: "firstName" },
];

type ColumnType = TypeOfColumn<typeof columns[0]>;
/* Output

    type ColumnType = {
        [x: string]: string;
    }
*/

type ColumnsType = TypeOfColumns<typeof columns>;
/* Output

type ColumnsType = {
    [x: string]: TypeOfColumn<Readonly<{
        type: "numeric" | "text";
        name: string;
    }>>;
}
*/

推荐答案

让我们从columns开始吧.柱的类型当前为Column[].因此,在column上使用typeof将计算为Column[].

相反,您希望编译器通过移除类型批注来将文本类型转换为infer.这需要用as const来完成,这样编译器就可以推断文字类型,而不仅仅是string.或者,您可以使用satisfies readonly Column[]来验证类型.

const columns = [
    { type: "numeric", name: "id" },
    { type: "text", name: "firstName" },
] as const satisfies readonly Column[]

现在必须将TypeOfColumns的约束更改为接受readonly个array.类型内的映射逻辑也需要更改.我们绘制的 map 是T[number],而不是T[number]["name"].每个联合成员K可用于提取属性名称K["name"]和对应的类型K["type"].

type TypeOfColumns<T extends readonly Column[]> = {
    [K in T[number] as K["name"]]: K["type"] extends "numeric" 
      ? number 
      : string;
};

type ColumnType = TypeOfColumn<typeof columns[0]>;
/*
    type ColumnType = {
        id: number;
    }
*/

type ColumnsType = TypeOfColumns<typeof columns>;
/*
    type ColumnsType = {
        id: number;
        firstName: string;
    }
*/

Playground

Typescript相关问答推荐

如何使函数接受类型脚本中具有正确类型的链接修饰符数组

使用axios在ngOnInit中初始化列表

适当限制泛型函数中的记录

如何在react组件中使用doctype和html标签?

有没有可能产生输出T,它在视觉上省略了T中的一些键?

Vue3 Uncaught SyntaxError:每当我重新加载页面时,浏览器控制台中会出现无效或意外的令牌

Angular:ngx-echart 5.2.2与Angular 9集成错误:NG 8002:无法绑定到选项,因为它不是div的已知属性'

ANGLE NumberValueAccessor表单控件值更改订阅两次

为什么发送空字段?

打印脚本中正则函数和函数表达式的不同类型缩小行为

设置不允许相同类型的多个参数的线性规则

如何创建一个将嵌套类属性的点表示法生成为字符串文字的类型?

如何在Type脚本中创建一个只接受两个对象之间具有相同值类型的键的接口?

带有';的类型脚本嵌套对象可选属性错误满足';

我可以将一个类型数组映射到TypeScrip中的另一个类型数组吗?

基于闭包类型缩小泛型类型脚本函数的范围

解析错误:DeprecationError: 'originalKeywordKind' 自 v5.0.0 起已被弃用,无法再使用

判断了可选的键值对象,但仍然得到xxx在Typescript 中可能是未定义

使用 next.js 时Typescript 上的错误数据类型

页面加载时样式未正确加载