繁体   English   中英

基于泛型类型的可选属性

[英]Optional properties based on generic type

我想根据泛型类型将属性设为可选。 我尝试了以下方法:

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" };

所以想法是仅为Option<'text'>定义属性text ,为Option<'audio' | 'video'>仅定义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'> interface Option<T extends 'text' | 'audio' | 'video'> 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;
}

所以; 当您想使用它们时,您必须在它是基于类型的媒体或文本选项之间转换为特定类型。

let option: Option = {id:'1',type: 'audio'}

if(option.type === 'audio'){
let media = option as MediaOption
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM