2017-09-20 119 views
2

我想编写一个名为ProptyDontHaveChildren接口,没有性态称为children如何定义在TypeScript中没有某些属性的接口?

type ChildrenType = Array<number> 
interface ProptyDontHaveChildren { 
    // doesn't have property called children 
    [index: string]: string; 
} 
interface WithChildren { 
    children: ChildrenType 
} 
type IntersectionType = ProptyDontHaveChildren & WithChildren; 

function createElement(type: string, props: ProptyDontHaveChildren, ...children: ChildrenType) { 
    const newProps:IntersectionType = { children: children, ...props } 
    //TODO ... 
} 

如何界定其不具有打字稿一些物业的接口?

+0

不能;如何在创建newProps之前删除道具['children'],甚至是简单的:'newProps = {...道具}; newProps.children =儿童'? –

回答

2

这里有相当多的问题。警告:


你可以做childrennever型或ProptyDontHaveChildrenundefined的可选属性(该属性是可选很重要):

type ChildrenType = Array<number> 
interface ProptyDontHaveChildren { 
    [index: string]: string; 
    children?: never; // note the ? 
} 

这保证ProptyDontHaveChildren只能从创建缺少或未定义的children属性。


但现在的交集IntersectionType不会是你想要的东西:它也不能有children因为交集要求是childrenundefined类型和ChildrenType型的,这是不可能发生的:

let oops: IntersectionType = { children: [1, 2, 3] } // error 

因此最好的做法是将ProptyDontHaveChildren定义为基类Propty类型与WithoutChildren类型的交集,以便您可以定义ProptyHaveChildren(您要的是IntersectionType)作为ProptyWithChildren的交点。像这样:

interface Propty { 
    [index: string]: string; 
} 
interface WithoutChildren { 
    children?: never 
} 
interface WithChildren { 
    children: ChildrenType 
} 
type ProptyDontHaveChildren = Propty & WithoutChildren 
type ProptyHaveChildren = Propty & WithChildren 

但仍然存在问题。 ProptyHaveChildren类型仍然不能有children类型的属性,因为索引签名要求每个属性包括children都是string类型。所以children必须是一个stringnumber阵列,这是不可能发生的:

const proptyHaveChildren: ProptyHaveChildren = { 
    a: "a", 
    children: [1, 2, 3] 
}; // error! 

function createElement(type: string, props: ProptyDontHaveChildren, ...children: ChildrenType) { 
    // error! 
    const newProps:ProptyHaveChildren = { children: children, ...props } 
} 

在这里,我不知道你怎么想继续。 TypeScript缺少,这就是你需要说的索引签名应该指的是每string密钥,除了"children"。你可以打通Propty类型,这样每一个属性是一个stringnumber秒的数组:

interface Propty { 
    [index: string]: string | ChildrenType; 
} 

function createElement(type: string, props: ProptyDontHaveChildren, ...children: ChildrenType) { 
    // no error 
    const newProps:ProptyHaveChildren = { children: children, ...props } 
} 

这样的作品,但现在每个属性将接受numbers数组:

const proptyHaveChildren: ProptyHaveChildren = { 
    a: [1, 2, 3], 
    children: [1, 2, 3] 
}; // no error! 

这可能不是你想要的。


在这一点上,我注意到我正在与TypeScript战斗,迫使它理解你的界面。也许做的最好的事情是改变你的Propty表示,使得它包含两个属性:一个props属性来保存所有这些string属性,children

type ChildrenType = Array<number> 

interface Propty { 
    props: { [index: string]: string } 
} 
interface WithoutChildren { 
    children?: never 
} 
interface WithChildren { 
    children: ChildrenType 
} 
type ProptyDontHaveChildren = Propty & WithoutChildren 
type ProptyHaveChildren = Propty & WithChildren 

const proptyHaveChildren: ProptyHaveChildren = { props: { a: "a" }, children: [1, 2, 3] }; // works 

function createElement(type: string, props: ProptyDontHaveChildren, ...children: ChildrenType) { 
    const newProps: ProptyHaveChildren = { children: children, props: props.props } // works 
} 

现在打字稿了解到,和一切正常...代价是将你的类型分成多个子属性。你可能更喜欢你的原始结构。无论您是否愿意处理上述问题,都取决于您。


希望有所帮助。祝你好运!

+0

非常感谢。 – xiang

1

您可以使用类型never,表明children不应ProptyDontHaveChildren存在:

type ChildrenType = Array<number> 
interface ProptyDontHaveChildren { 
    [index: string]: string; 
    children: never; 
} 
interface WithChildren { 
    children: ChildrenType 
} 
type IntersectionType = ProptyDontHaveChildren & WithChildren; 

function createElement(type: string, props: ProptyDontHaveChildren, ...children: ChildrenType) { 
    // OK. No error 
    const newProps:IntersectionType = { children: children, ...props } 
} 
+0

不幸的是,这个解决方案存在问题,当您尝试创建上述类型的实例时,这个问题就变得很明显。请参阅[我的回答](https://stackoverflow.com/a/46322516/2887218)以获取更多信息。 – jcalz

相关问题