2017-08-16 47 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