用于检测重复对象(例如多语言字段)中缺失属性的类型定义规则
A type-definition rule to detect missing properties in repeating objects (e.g. multi language fields)
假设我有这样一个类型定义:
export type TextMessagesType = {
[language: string]: {
[placeholder: string]: string;
};
};
适合这种情况:
export const TextMessages: TextMessagesType = {
en: {
noText: 'No Texts available!',
},
};
现在,如果我想添加新语言和新属性,例如:
export const TextMessages: TextMessagesType = {
en: {
noText: 'No Texts available!',
welcome: 'You are welcome'
},
de: {
noText: 'Keine weiteren Texte vorhanden!',
// welcome missing
},
};
我想确保 de
-对象与 en
-对象具有完全相同的属性。由于类型定义,IDE 应该识别缺失的属性(例如,welcome
)。
我可以借助打字稿类型定义规则来做到这一点吗?如果是,如何?
编辑:对不起,我想,缺少一个重要信息:
识别机制应该依赖于每个对象中的现有属性。假设 de
对象有一个 属性 xy
而它在 en
对象中丢失,反之亦然。如果一个语言对象获得了一个新的 属性,它应该在所有其他语言对象中被标记为缺失 属性。
我们可以使用联合类型的字符串来实现这一点,在键的类型上使用 in
关键字:
type RequiredLanguageFields = 'welcome'
| 'noText';
type TextMessagesType = {
[language: string]: {
[placeholder in RequiredLanguageFields]: string;
};
};
const TextMessages: TextMessagesType = {
en: {
noText: 'No Texts available!',
welcome: 'You are welcome'
},
de: { // type error on this line
noText: 'Keine weiteren Texte vorhanden!',
// welcome missing
},
};
Property 'welcome' is missing in type '{ noText: string; }' but required in type '{ welcome: string; noText: string; }'.(2741)
需要做一些额外的工作,因为您需要先定义所需的字段,然后再将它们添加到对象中。或者你可以有一些主翻译对象并使用它的键来定义其他所需的键:
const enStrings = {
noText: 'No Texts available!',
welcome: 'You are welcome',
};
type TextMessagesType = {
[language: string]: {
[placeholder in keyof typeof enStrings]: string;
};
};
根据对您问题的修改,我将尝试描述为什么我认为无法按照您希望的方式创建类型。
现在我们说所有值都必须是同一类型的对象 - 它们必须都具有相同的属性,并且所有这些属性都必须是字符串。但那是什么类型?我们可能会定义一些采用通用接口的接口:
interface ITextMessagesType<T> {
[language: string]: {
[placeholder in keyof T]: string;
};
};
const TextMessages: ITextMessagesType = { // error here as we have no passed in the type for the generic `T`
en: {
noText: 'No Texts available!',
welcome: 'You are welcome'
},
de: { // type error on this line
noText: 'Keine weiteren Texte vorhanden!',
// welcome missing
},
};
我们仍然需要定义泛型是什么;我们回到您在上面给出的原始示例中遇到的问题 - 您需要在定义对象之前定义键。
在函数中更容易一些,因为我们可以从传入的对象中推断出类型。但是接下来我们进入下一个问题;哪个对象被视为所需类型?以下面的代码为例:
const test = <T>(x: { [key: string]: { [key in keyof T]: string } }) => true;
const x = test({
en: {
noText: 'No Texts available!',
welcome: 'You are welcome', // now we get a type error here
},
de: {
noText: 'Keine weiteren Texte vorhanden!',
// welcome missing
},
})
我们得到的错误是:
Type '{ noText: string; welcome: string; }' is not assignable to type
'{ noText: string; }'. Object literal may only specify known
properties, and 'welcome' does not exist in type '{ noText: string;
}'.(2322)
此处 Typescript 已确定 de
处的值是 'master' 类型 - 因此在我们尝试在 welcome
上定义键时出现错误=17=].
因此我不相信你能得到你想要的东西 - 希望有人会进来证明我错了。
假设我有这样一个类型定义:
export type TextMessagesType = {
[language: string]: {
[placeholder: string]: string;
};
};
适合这种情况:
export const TextMessages: TextMessagesType = {
en: {
noText: 'No Texts available!',
},
};
现在,如果我想添加新语言和新属性,例如:
export const TextMessages: TextMessagesType = {
en: {
noText: 'No Texts available!',
welcome: 'You are welcome'
},
de: {
noText: 'Keine weiteren Texte vorhanden!',
// welcome missing
},
};
我想确保 de
-对象与 en
-对象具有完全相同的属性。由于类型定义,IDE 应该识别缺失的属性(例如,welcome
)。
我可以借助打字稿类型定义规则来做到这一点吗?如果是,如何?
编辑:对不起,我想,缺少一个重要信息:
识别机制应该依赖于每个对象中的现有属性。假设 de
对象有一个 属性 xy
而它在 en
对象中丢失,反之亦然。如果一个语言对象获得了一个新的 属性,它应该在所有其他语言对象中被标记为缺失 属性。
我们可以使用联合类型的字符串来实现这一点,在键的类型上使用 in
关键字:
type RequiredLanguageFields = 'welcome'
| 'noText';
type TextMessagesType = {
[language: string]: {
[placeholder in RequiredLanguageFields]: string;
};
};
const TextMessages: TextMessagesType = {
en: {
noText: 'No Texts available!',
welcome: 'You are welcome'
},
de: { // type error on this line
noText: 'Keine weiteren Texte vorhanden!',
// welcome missing
},
};
Property 'welcome' is missing in type '{ noText: string; }' but required in type '{ welcome: string; noText: string; }'.(2741)
需要做一些额外的工作,因为您需要先定义所需的字段,然后再将它们添加到对象中。或者你可以有一些主翻译对象并使用它的键来定义其他所需的键:
const enStrings = {
noText: 'No Texts available!',
welcome: 'You are welcome',
};
type TextMessagesType = {
[language: string]: {
[placeholder in keyof typeof enStrings]: string;
};
};
根据对您问题的修改,我将尝试描述为什么我认为无法按照您希望的方式创建类型。
现在我们说所有值都必须是同一类型的对象 - 它们必须都具有相同的属性,并且所有这些属性都必须是字符串。但那是什么类型?我们可能会定义一些采用通用接口的接口:
interface ITextMessagesType<T> {
[language: string]: {
[placeholder in keyof T]: string;
};
};
const TextMessages: ITextMessagesType = { // error here as we have no passed in the type for the generic `T`
en: {
noText: 'No Texts available!',
welcome: 'You are welcome'
},
de: { // type error on this line
noText: 'Keine weiteren Texte vorhanden!',
// welcome missing
},
};
我们仍然需要定义泛型是什么;我们回到您在上面给出的原始示例中遇到的问题 - 您需要在定义对象之前定义键。
在函数中更容易一些,因为我们可以从传入的对象中推断出类型。但是接下来我们进入下一个问题;哪个对象被视为所需类型?以下面的代码为例:
const test = <T>(x: { [key: string]: { [key in keyof T]: string } }) => true;
const x = test({
en: {
noText: 'No Texts available!',
welcome: 'You are welcome', // now we get a type error here
},
de: {
noText: 'Keine weiteren Texte vorhanden!',
// welcome missing
},
})
我们得到的错误是:
Type '{ noText: string; welcome: string; }' is not assignable to type '{ noText: string; }'. Object literal may only specify known properties, and 'welcome' does not exist in type '{ noText: string; }'.(2322)
此处 Typescript 已确定 de
处的值是 'master' 类型 - 因此在我们尝试在 welcome
上定义键时出现错误=17=].
因此我不相信你能得到你想要的东西 - 希望有人会进来证明我错了。