javascript - 为什么 TypeScript 在编译时无法检测到不匹配的类型以及如何修复它?
问题描述
在我们的代码库中,我们有如下代码,它无法检测是否type violation
由于程序员错误而发生 - 为什么会发生这种情况以及解决此问题的最佳方法是什么?
// forcing a structure on "shape" of the output
interface IPayloadOutput {
[key: string]: string
}
interface MyPayloadOutput extends IPayloadOutput {
myPayloadKey1: string
myPayloadKey2: string
extraKey: string //adding this here doesn't cause compile error if it's not returned
}
// Input data needs that to be transformed to the output
interface MyPayloadInput {
data1: string
data2: string
}
class MyPayloadOutputGenerator extends PayloadOutputGenerator {
public getPayloadKeyValues(args: MyPayloadInput): IPayloadKeyValues {
return {
myPayloadKey1: {key1: args.data1, key2: args.data2},
myPayloadKey2: { key1: args.data1 + '-senor' },
// Why does code not throw compile error if the below field is missing?
// extraKey: { key1: 'extra' }
}
}
}
function consumer(response: MyPayloadOutput): void {
console.log(response)
}
const x = new MyPayloadOutputGenerator().getPayloadOutput<MyPayloadInput, MyPayloadOutput>({
data1: 'hello',
data2: 'wrold',
})
consumer(x) // should throw compiler error if missing `extraString`
PayloadGenerator
接受并将其Input
转换为预期的Output
。但是返回的数据中缺少key extraString
inMyPayloadOutput
却没有报编译错误?这是为什么?
这是一个显示正在运行的示例的小提琴
为了完整起见,这里是PayloadGenerator
:
// all payloads need key1 and an optional key2.
interface IPayloadDetails {
key1: string
key2?: string
}
// force structure for how we expect payload key/values to look
interface IPayloadKeyValues {
[key: string]: IPayloadDetails
}
abstract class PayloadOutputGenerator {
// source keys from implementing classes. `args` is not typed to be 'anything'
public abstract getPayloadKeyValues(args): IPayloadKeyValues
// Generic method to be used with any input/output combo
public getPayloadOutput<Input, Output>(args: Input): Output {
const payloadKeyValues = this.getPayloadKeyValues(args)
const payloadOutput = {} as Output
Object.keys(payloadKeyValues).forEach(key => {
payloadOutput[key] = JSON.stringify(payloadKeyValues[key]) //do custom encoding here
})
return payloadOutput
}
}
解决方案
您在中心位置()进行了类型转换(as Output
)并省略: IPayloadKeyValues
了打字,并且总体上针对打字稿类型系统工作。通过使用索引类型,打字稿无法确定代码的实际作用。相反,从一开始就使用泛型:
abstract class PayloadOutputGenerator<I, O extends {}> { // already introduce the generic here ...
public abstract getPayloadKeyValues(args: I): O // then you can narrow down this correctly
public getPayloadOutput(args: I) { // and this gets typed correctly automatically
const payloadKeyValues = this.getPayloadKeyValues(args);
const payloadOutput = {} as { [K in keyof O]: string }; // its a mapped type, so lets type it as such
Object.keys(payloadKeyValues).forEach(key => {
payloadOutput[key] = JSON.stringify(payloadKeyValues[key]) //do custom encoding here
});
return payloadOutput
}
}
推荐阅读
- regex - 替换所有其他数字
- javascript - 将 DIV 映射到 Vimeo/Youtube 时间戳
- colors - 根据乌龟自己的变量更改 NetLogo 中代理的颜色
- gulp - local web server can't see folder on level up entry point
- javascript - Call child method class in parent with parent instance
- python - Celery 任务时间什么时候开始计算?
- cmd - 命令提示符自动写入日志文件
- c - Error when passing multidimensional char array to a void function in C
- python - 处理数据框 pandas 中的数据
- mysql - 更新记录时如何避免mysql中的这个错误?