typescript 如何创建使用有关对象的信息来推断新类型的类型帮助器

jobtbby3  于 2023-01-14  发布在  TypeScript
关注(0)|答案(1)|浏览(120)

有一个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 };

我以为我可以通过使用extends读取值来做到这一点,但它根本不起作用。

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;
    }>>;
}
*/
2vuwiymt

2vuwiymt1#

让我们从columns开始。列的类型当前为Column[]。因此,在column上使用typeof将计算为Column[]
您希望编译器通过删除类型注解来 * 推断 * 文本类型。这需要使用as const来完成,以便编译器推断文本类型而不仅仅是string。可选地,您可以使用satisfiesreadonly Column[]来验证类型。

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

TypeOfColumns的约束现在必须更改为接受readonly数组。类型内部的Map逻辑也需要更改。我们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

相关问题