2017-08-16 46 views
0

我如何定义这些对象的接口:固定数量的动态命名的键对象接口

let bob = { 
    Bob: { 
    age: 9, 
    gender: 'M' 
    } 
}; 
let alice = { 
    Alice: { 
    age: 12, 
    gender: 'F' 
    } 
}; 

我可以使用的解决方案,从this thread,但实在是太宽容,我想该用例限制到一个独特的(或固定数量)的密钥。

BONUS如果你能弄清楚如何表达:

  • 多少个键被允许在顶级对象
  • 指定每个关键

像这样的事情不同的接口伪代码:

interface funnyEdge { 
    <string>from: fromEdge, 
    <string>to: toEdge 
} 
let edge: funnyEdge = {foo: {...}, bar: {...}} 
+0

我认为你正在试图做的是非常相似的字典正如你所提到的那样,控制键的数量是静态类型系统无法执行的运行时概念。 – Reza

+0

'interface foo {bar:baz}'确实执行特定数量的密钥否? – Renaud

+1

它强制执行特定数量的键并且强制执行只有名为'bar'的类型为'baz'的字段。你不能说“这个对象只有一个'baz'类型的字段,但我不知道这个键的名字现在是什么 ”。 – y2bd

回答

0

现在原来是有办法做到这一点:

type Peeps = 'Bob'|'Alice'; 
type Def = { ... }; 
type Person = {[name in Peeps]?: Def } 
// or if you're so inclined 
type Person = Map<Peeps,Def> 

// here with the other example 
type EdgeEnd = 'from'|'to'; 
type FunnyNode = { ... }; 
type FunnyEdge = {[end in EdgeEnd]: FunnyNode}; 
+0

这是如何回答你原来的问题?如果您在设计时知道您将接受的确切密钥,则可以使用“记录”。但这不是你的问题似乎在问的问题。如前所述,它询问如何使用固定数量的* runtime-specified *键,这仍然是不可能的。 – jcalz

+0

我编辑了答案,表明它符合法案。它在问题中提到_unique keys_在当时我困惑的想法可能意味着预先定义的问题,但我同意这个问题措辞不当。 – Renaud

1

喜欢这个?

interface Person { 
    age: number; 
    gender: "M" | "F"; 
} 

interface Bob extends Person { 
    //... 
} 

interface Alice extends Person { 
    //... 
} 

interface Members { 
    Bob?: Bob; 
    Alice?: Alice; 
} 

let bob: Members = { 
    Bob: { 
    age: 9, 
    gender: 'M' 
    } 
}; 
let alice: Members = { 
    Alice: { 
    age: 12, 
    gender: 'F' 
    } 
}; 

alert(alice.Alice.age) // ok 
alice.Bob = bob.Bob // ok 
alert(alice.Eve.age) // error 

Try it in the Playground

2

类型系统中打字稿不允许你指定与非指定键指定数目的一个类型。实际上,由于它缺少exact types,因此TypeScript实际上并不允许您指定具有指定数字键的类型,也可以指定键。它只对对象文字进行多余的属性检查。作为一种类型,是这样的:

type Person = { 
    age: number, 
    gender: 'M' | 'F' | 'O' 
} 

并不意味着Person不能有其他的按键,如:

const pirate = { 
    age: 35, 
    gender: 'M' as 'M', 
    legs: 1, 
    parrot: true 
}; 
const piratesArePeopleToo: Person = pirate; // no problem 

所以最你能希望将是打字稿抱怨,如果你通过一个对象文字太多的键,如在:

const otherPirate: Person = { 
    age: 40, 
    gender: 'F', 
    eyes: 1, 
    parrot: false 
}; // error 

而且,不,TypeScript不会让你表达这种约束,据我所知。


我能想到的将是一个解决办法的最好:创造一个函数,它接受一个键和Person,并返回你想要的类型的对象:如果您组织

type NamedPerson<K extends string> = Record<K, Person>; 
function makeNamedPerson<K extends string>(key: K, person: Person): NamedPerson<K> { 
    let namedPerson = {} as NamedPerson<K>; 
    namedPerson[key]=person; 
    return namedPerson; 
} 
const namedPerson = makeNamedPerson('chris', { age: 10, gender: 'O' }); 
console.log(namedPerson.chris.age); 

你的代码所以获得类型为NamedPerson<K>的对象的唯一合理方法是调用函数makeNamedPerson()(例如,仅导出函数并使其类型与private成员生成类),然后您知道每个函数都会有一个单键。这对于你来说不如被类型系统强制执行,但是至少让你的库的用户难以规避约束。

希望有帮助;祝你好运!

1

这个怎么样?

type Person<TName extends string> = { 
    [key in TName]: { 
    age: number, 
    gender: 'M'|'F' 
    } 
}; 

var alice: Person<"Alice">; 
alice.Alice.age = 42; 

alice.AnythingElse // error; 

和多键:

var johnAndMary: Person<"John" | "Mary">; 
johnAndMary.John.age; 
johnAndMary.Mary.gender; 
johnAndMary.Don // error 
+1

只在昨天开始,我已经爱上它! – Renaud