基于泛型类型的可选属性



我想根据泛型类型使一个属性成为可选的。我尝试了以下方法:

interface Option<T extends 'text' | 'audio' | 'video'> {
id: string;
type: T;
text: T extends 'text' ? string : undefined;
media: T extends 'audio' | 'video' ? T : undefined;
}
const option: Option<'text'> = { text: "test", type: "text", id: "opt1" };

因此,思想是属性text仅为Option<'text'>定义,media仅为Option<'audio' | 'video'>定义。

但是,ts编译器给了我以下错误:

Property 'media' is missing in type '{ text: string; type: "text"; id: string; }' 
but required in type 'Option<"text">'.ts(2741)

我该如何解决这个问题?

不能让属性的可选性依赖于接口中的泛型类型参数。但是,您可以使用类型别名和交叉:

type Option<T extends 'text' | 'audio' | 'video'> = {
id: string;
type: T;
} 
& (T extends 'text' ? { text: string } : {})
& (T extends 'audio' | 'video' ? { media: T }: {});

const option: Option<'text'> = { text: "test", type: "text", id: "opt1" };

玩尽管使用歧视联合可能会更好:

type Option = 
| { id: string; type: 'text'; text: string }
| { id: string; type: 'audio' | 'video'; media: 'audio' | 'video' };

const option: Extract<Option, {type: 'text' }> = { text: "test", type: "text", id: "opt1" };
function withOption(o: Option) {
switch(o.type) {
case 'text': console.log(o.text); break;
default: console.log(o.media); break;
}
}

操场上联系

您可以使用联合:

type Option<T extends 'text' | 'audio' | 'video'> =
{
id: string;
type: T;
}
&
(
T extends 'text'
? {text: string}
: {media: T}
);
const option: Option<'text'> = { text: "test", type: "text", id: "opt1" };

操场上联系

这是不可能有一个泛型类型使用字符串值像你提到的,interface Option<T extends 'text' | 'audio' | 'video'>

但是如果你想要使用下面的内容:

  • option.ts
interface Option {
id: string;
type: 'text' | 'audio' | 'video' | undefined;
}
  • media-option.ts
interface MediaOption extends Option {
media: string;
}
  • text-option.ts
interface TextOption extends Option {
text: string;
}

;当你想要使用它们时,你必须将其转换为特定的类型,如果它是基于type的media或text选项。

let option: Option = {id:'1',type: 'audio'}
if(option.type === 'audio'){
let media = option as MediaOption
}

最新更新