我在TypeScript中建模API请求格式:
interface ApiTerm {
term: {
name: string,
value: string,
}
}
interface ApiAnd {
and: {
lhs: ApiItem,
rhs: ApiItem,
}
}
interface ApiOr {
or: {
lhs: ApiItem,
rhs: ApiItem,
}
}
type ApiItem =
| ApiTerm
| ApiAnd
| ApiOr
;
这行得通,但是我将需要实现除“ and”和“ or”之外的许多二进制操作,因此我想以某种方式来缩短和重用代码。
在我编写了一些在接口中使用特定字符串枚举值的其他代码之后,我尝试使用字符串枚举作为属性名称:
enum Operation {
And = "and",
Or = "or",
}
interface ApiBinary<O extends Operation> {
[O]: {
lhs: ApiItem,
rhs: ApiItem,
}
}
type ApiItem =
| ApiTerm
| ApiBinary<Operation.And>
| ApiBinary<Operation.Or>
;
不幸的是,这会产生TypeScript 2.9.1错误:
A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.
有没有一种替代解决方案,可以使我避免写出仅键名不同的大量重复接口?
查看错误消息的“唯一符号”类型,我不相信可以基于Symbol
s创建枚举。
在TypeScript界面中使用字符串枚举值作为计算的属性键似乎非常接近,但是它涉及在接口中使用特定的字符串枚举值,该接口在较新的TypeScript版本中可以直接使用。
除了使用计算属性之外,还可以使用映射类型:
interface ApiTerm {
term: {
name: string,
value: string,
}
}
enum Operation {
And = "and",
Or = "or",
}
type ApiBinary<O extends Operation> = {[o in O]: {
lhs: ApiItem,
rhs: ApiItem,
}
}
type ApiItem =
| ApiTerm
| ApiBinary<Operation.And>
| ApiBinary<Operation.Or>
;
const andExample: ApiBinary<Operation.And> = {
'and': {
lhs: { term: { name: 'a', value: 'b' } },
rhs: { term: { name: 'c', value: 'd' } }
}
}
但是,请注意,没有办法表达ApiBinary
只能具有一个属性的限制。例如,有人可以声明type N = ApiBinary<Operation.And | Operation.Or>;
当使用映射类型时,它不能与计算属性很好地混合-ApiItem
在此示例中,编译器无法推断计算属性类型符合约束:
const foo = ({ kind, lhs, rhs }: { kind: Operation, lhs: ApiItem, rhs: ApiItem }): ApiItem =>
({ [kind]: { lhs, rhs } });
该错误is not assignable to type 'ApiBinary<Operation.Or>'
之所以存在,是因为编译器尝试检查对所有联合成员的可分配性,如果失败,则仅告知最后一个。
我认为编写此函数的唯一方法是冗长的:
const foo = <O extends Operation>({ kind, lhs, rhs }: { kind: O, lhs: ApiItem, rhs: ApiItem }) => {
const result = {} as ApiBinary<O>;
result[kind] = {lhs, rhs};
return result;
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句