我有一些不同的接口和对象,每个接口和对象都有一个type
属性。假设这些是存储在NoSQL数据库中的对象。如何基于输入参数getItem
创建具有确定返回类型的泛型type
函数?
interface Circle {
type: "circle";
radius: number;
}
interface Square {
type: "square";
length: number;
}
const shapes: (Circle | Square)[] = [
{ type: "circle", radius: 1 },
{ type: "circle", radius: 2 },
{ type: "square", length: 10 }];
function getItems(type: "circle" | "square") {
return shapes.filter(s => s.type == type);
// Think of this as items coming from a database
// I'd like the return type of this function to be
// deterministic based on the `type` value provided as a parameter.
}
const circles = getItems("circle");
for (const circle of circles) {
console.log(circle.radius);
^^^^^^
}
类型'Circle |类型中不存在属性'radius'正方形”。
答案 0 :(得分:2)
您正在寻找overload signatures
function getItems(type: "circle"): Circle[]
function getItems(type: "square"): Square[]
function getItems(type: "circle" | "square") {
return shapes.filter(s => s.type == type);
}
在实际定义之前放置多个类型签名,使您可以列出函数签名可能属于的不同“情况”。
评论后编辑
事实证明,您想要的是可能,但是我们可能必须跳过几圈才能到达目的地。
首先,我们需要一种翻译每个名称的方法。我们希望"circle"
映射到Circle
,"square"
映射到Square
,依此类推。为此,我们可以使用conditional type。
type ObjectType<T> =
T extends "circle" ? Circle :
T extends "square" ? Square :
never;
(我使用never
作为后备,希望如果您以某种方式最终以无效的类型结束,它会很快产生类型错误)
现在,我不知道像您所要求的那样对函数调用的类型进行参数化的方法,但是Typescript 确实支持通过以下方式对对象的键进行参数化: mapped typed。因此,如果您愿意使用getItems("circle")
的{{1}}语法进行交易,我们至少可以描述该类型。
getItems["circle"]
问题是,我们现在必须构造这种类型的对象。假设您要定位ES2015(编译时为interface Keys {
circle: "circle";
square: "square";
}
type GetItemsType = {
[K in keyof Keys]: ObjectType<K>[];
}
或更高版本),则可以使用Javascript Proxy
类型。现在,不幸的是,我不知道有什么好方法可以说服Typescript我们正在做的事还可以,因此快速浏览--target es2015
可以消除它的疑虑。
any
因此,您将失去对实际let getItems: GetItemsType = <any>new Proxy({}, {
get: function(target, type) {
return shapes.filter(s => s.type == type);
}
});
“功能”的类型检查,但是在呼叫站点上获得了更强大的类型检查。然后,拨打电话,
getItems
这值得吗?这取决于你。这是很多额外的语法,您的用户必须使用const circles = getItems["circle"];
for (const circle of circles) {
console.log(circle.radius);
}
表示法,但是它会得到您想要的结果。
答案 1 :(得分:2)
答案 2 :(得分:-2)
As you have mentioned that data is comming from No-Sql database with a type property. you can create type property as string value and change your interfaces as a class to check instanceOf in your function.
class Circle {
type: string;
radius: number;
}
class Square {
type: string;
length: number;
}
const shapes: (Circle | Square)[] = [
{ type: "circle", radius: 1 },
{ type: "circle", radius: 2 },
{ type: "square", length: 10 }];
function getItems(type: string) {
return shapes.filter(s => s.type == type);
// Think of this as items coming from a database
// I'd like the return type of this function to be
// deterministic based on the `type` value provided as a parameter.
}
const circles = getItems("circle");
for (const circle of circles) {
if (circle instanceof Circle) {
console.log(circle.radius);
} else if (circle instanceof Square) {
console.log(circle.length);
}
}