使用 TypeScript 对带有前缀的 JSON 文件键的类型定义

Posted

技术标签:

【中文标题】使用 TypeScript 对带有前缀的 JSON 文件键的类型定义【英文标题】:Type Definition for JSON file Keys with Prefix using TypeScript 【发布时间】:2021-07-26 02:27:28 【问题描述】:

我正在将 JSON 文件导入到我的 TypeScript 程序中,如下所示:(我在 tsconfig.json 中启用了 resolveJsonModule

import data from './sample.json';

很高兴,我注意到从 JSON 文件接收到的对象是强类型的。然后我编写了一个函数,该函数根据参数访问所述 JSON 对象的某个键:

export const get = (key: keyof typeof data): void => 
    console.log(data[key]); // example code
;

这按预期工作,我的函数的使用者会知道 JSON 文件中接受/包含哪些值。问题来了:我希望我的函数的使用者只能访问我前缀的某些键(在以下示例中,前缀是 prefix_):

export const get = (key: keyof typeof data): void => 
    console.log(data[`prefix_$key`]);
;

我必须如何更改我的类型定义才能使其仍然有效?

【问题讨论】:

【参考方案1】:

TypeScript 4.3 之前

从 TypeScript 4.2 开始,无法在使用字符串函数的情况下执行条件类型,因此我不知道如何指定以前缀开头的键。

我能想到的最好的方法是使用 Pick utility type 从所有可能属性的交集和 json 文件的派生类型创建一个新类型。

在下面的示例中,我导入了两个示例 json 文件。接下来,我指定所有可能的键以保留在字符串文字类型中。然后使用 Pick 从这两个文件中创建两种类型。为了让 Pick 工作,我必须在第二个参数中传递一个类型,它是派生文件类型和 PublicPrefix 类型的键的交集。

import data1 from './sample1.json'; //  x: 1, prefix_A: 2, prefix_B: 3 
import data2 from './sample2.json'; //  y: 1, prefix_B: 2, prefix_C: 3 
type PublicPrefix = 'prefix_A' | 'prefix_B' | 'prefix_C';
export type Data1 = Pick<typeof data1, keyof typeof data1 & PublicPrefix>;
// Data1 =  prefix_A: number, prefix_B: number 
export type Data2 = Pick<typeof data2, keyof typeof data2 & PublicPrefix>;
// Data2 =  prefix_B: number, prefix_C: number 

如果 data1 具有属性 prefix_Aprefix_B,而 data2 具有属性 prefix_Bprefix_C,则结果类型将是 Data1 = prefix_A, prefix_B Data2 = prefix_B, prefix_C ,所有其他键都被排除在外。

TypeScript 4.3 中的模板字符串文字

TypeScript 4 引入了模板字符串文字,在 4.3 版中,它们增强了功能,因此您可以指定上下文类型的模板。这允许您在模板中指定一个类型,将模板的这些部分扩展为对该类型有效的任何内容。

在下面的示例中,创建了一个模板字符串文字,它以 prefix_ 开头,后跟任何字符串。通过以与上例相同的方式使用 Pick,生成的类型将仅包含以 prefix_ 开头的属性。

import data from './sample.json';
type PublicPrefix = `prefix_$string`;
export type Data1 = Pick<typeof data, keyof typeof data & PublicPrefix>;

【讨论】:

以上是关于使用 TypeScript 对带有前缀的 JSON 文件键的类型定义的主要内容,如果未能解决你的问题,请参考以下文章

带有接口的Typescript中的Json枚举?

带有日期类型的 Typescript GET 对象

带有 TypeScript 解析器/插件的 ESLint:如何包含从 tsconfig.json 中排除的 .spec.ts?

带有命名空间和前缀的 Json 到 XML

Typescript - 从带有日期字符串的 Json 字符串自动转换为带有 Date 属性的对象

带有 ESLint 的 TypeScript:解析错误:关键字“枚举”是保留的 eslint