如何将静态字符串值(用于集合名称)映射到特定的返回类型?
type Apple = {
color: string
taste: string
}
type Banana = {
color: string
length: string
}
type Carrot = {
color: string
baby: boolean
}
function collection(collectionName: string) {
return function get() {
switch (collectionName) {
case 'apples':
return [{
color: 'red',
taste: 'great',
}];
case 'bananas':
return [{
color: 'yellow',
length: 'medium',
}];
case 'carrots':
return [{
color: 'orange',
baby: false,
}];
}
}
}
例如,在使用中,我希望它推断特定的集合名称("apples"
)将返回特定类型的数组(Apple
)。
collection('apples')() // => Apple[]
答案 0 :(得分:2)
@NurbolAlpysbayev的回答很好,并且会超载。
或者,我通常尝试使用generics代替,因为它们倾向于与联合更好地结合。例如,您可以创建一个从水果名称到水果类型的映射:
interface FruitMap {
apples: Apple,
bananas: Banana,
carrots: Carrot
}
并使用keyof
and lookup types描述collectionName
与collection()
的输出之间的关系:
function collection<K extends keyof FruitMap>(collectionName: K): () => Array<FruitMap[K]>;
function collection(collectionName: keyof FruitMap): () => Array<FruitMap[keyof FruitMap]> {
return function get() {
switch (collectionName) {
case 'apples':
return [{
color: 'red',
taste: 'great',
}];
case 'bananas':
return [{
color: 'yellow',
length: 'medium',
}];
case 'carrots':
return [{
color: 'orange',
baby: false,
}];
}
}
}
这会导致它们正确键入:
const appleArray = collection("apples")();
// const appleArray: Apple[]
const appleOrBananaArray = collection(Math.random() < 0.5 ? "apples" : "bananas")();
// const appleOrBananaArray: (Apply | Banana)[]
希望有所帮助;祝你好运!
答案 1 :(得分:1)
Overloads非常适合您的用例。
function collection(collectionName: 'bananas'): () => Banana[]
function collection(collectionName: 'carrots'): () => Carrot[]
function collection(collectionName: 'apples'): () => Apple[]
function collection(collectionName: string) {/*... */ }
let v = collection('apples')() // Apple[]
答案 2 :(得分:0)
从答案的组合来看,在我的用例中,在接口声明中使用重载似乎是最优雅的解决方案。
type Apple = {
color: string
taste: string
}
type Banana = {
color: string
length: string
}
type Carrot = {
color: string
baby: boolean
}
interface TypedCollectionFactory {
(collectionName: 'apples'): () => Apple[]
(collectionName: 'bananas'): () => Banana[]
(collectionName: 'carrots'): () => Carrot[]
}
const collection: TypedCollectionFactory = function(collectionName: string) {
return function get() {
// ...
}
}
const apples = collection('apples')()
for (const apple of apples) {
console.log(apple.taste)
}