typescript能否在对象分配期间推断其他属性的类型
我正在从事一个大型Sanity.io CMS项目,该项目涉及编写大量JS来定义以下内容类型:typescript能否在对象分配期间推断其他属性的类型,typescript,type-inference,inference,Typescript,Type Inference,Inference,我正在从事一个大型Sanity.io CMS项目,该项目涉及编写大量JS来定义以下内容类型: const person = { type: 'document', name: 'person', fieldsets: [ { name: 'personalDetails', title: 'Personal Details' }, ], fields: [ { name: 'firstName', type: 'string', fieldset: 'pers
const person = {
type: 'document',
name: 'person',
fieldsets: [
{ name: 'personalDetails', title: 'Personal Details' },
],
fields: [
{ name: 'firstName', type: 'string', fieldset: 'personalDetails' },
{ name: 'surname', type: 'string', fieldset: 'personalDetails' },
],
}
我想知道是否可以创建一个文档接口/类型,该接口/类型可以推断提供的字段集
的名称,然后使用它们将字段
数组中对象的字段集
属性的类型限制为字符串文本的并集。这是一件小事,但它能让我在大量生产这些内容类型的同时利用autocomplete,从而加快开发速度
我最初的尝试是这样的:
interface Document {
type: 'document';
name: string;
fieldsets: ReadonlyArray<{ name: string; title: string; }>;
fields: Array<{
name: string;
type: string;
fieldset: this['fieldset'][number]['name']; // Error: A 'this' type is available only in a non-static member of a class or interface
}>
}
接口文档{
类型:“文件”;
名称:字符串;
字段集:ReadonlyArray;
字段:数组
}
我理解错误并尝试了各种解决方法,但如果不使用泛型类型并提供字段集名称数组,就无法实现我的目标:
interface Document<T extends ReadonlyArray<string>> {
/* ...rest of definition */
fieldset: ReadonlyArray<{ name: T[number] }>
fields: Array<{
name: string;
type: string;
fieldset: T[number];
}>
}
const person: Document<['personalDetails']> = {
/* works, but not exactly what I'm after */
}
接口文档{
/*…定义的其余部分*/
字段集:ReadonlyArray
字段:数组
}
施工人员:文件={
/*有效,但不完全是我想要的*/
}
那么,TypeScript是否有可能在分配期间动态推断该类型,或者我正在寻找不存在的内容?您正确地认为需要使用泛型来正确地键入该类型。Typescript无法从常量推断泛型。它可以从函数调用推断泛型。因此,这里要做的是定义一个identity函数作为创建类型安全文档的助手 我希望通过使用类型T来描述整个
fieldset
属性,而不仅仅是名称,从而获得更好的推断。但是我仍然必须使用作为const
,以便从对象属性中获取文本字符串值
type FieldSet = {
name: string;
title: string;
}
type Field = {
name: string;
type: string;
fieldset: string;
}
interface MyDocument<T extends ReadonlyArray<FieldSet>> {
type: 'document';
name: string;
fieldsets: T;
fields: Array<Field & {fieldset: T[number]['name']}>
}
const createDoc = <T extends ReadonlyArray<FieldSet>>(schema: MyDocument<T>): MyDocument<T> => schema;
const person = createDoc({
type: 'document',
name: 'person',
fieldsets: [
{ name: 'personalDetails', title: 'Personal Details' }
] as const,
fields: [
{ name: 'firstName', type: 'string', fieldset: 'personalDetails' },
{ name: 'surname', type: 'string', fieldset: 'otherSet' }, // error
],
});
// note: we need `as const` because the string is an object property
const identity = <T extends any>(value: T): T => value;
const a = identity('personalDetails'); // this infers a literal
const b = identity({ name: 'personalDetails', title: 'Personal Details' }); // this does not
类型字段集={
名称:字符串;
标题:字符串;
}
类型字段={
名称:字符串;
类型:字符串;
字段集:字符串;
}
接口MyDocument{
类型:“文件”;
名称:字符串;
字段集:T;
字段:数组
}
const createDoc=(模式:MyDocument):MyDocument=>schema;
const person=createDoc({
键入:“文档”,
姓名:'人',
字段集:[
{名称:'personalDetails',标题:'personalDetails'}
]作为康斯特,
字段:[
{name:'firstName',type:'string',fieldset:'personalDetails'},
{name:'names',type:'string',fieldset:'otherSet'},//错误
],
});
//注意:我们需要'as const',因为字符串是一个对象属性
常量标识=(值:T):T=>值;
常量a=标识('personalDetails');//这就推断出一个字面意义
const b=标识({name:'personalDetails',title:'personalDetails'});//这是不可能的