如何提示我不能控制的函数的类型?



当解析json格式的字符串时,我得到一个linter错误:

let mqttMessage = JSON.parse(message.toString())
// ESLint: Unsafe assignment of an `any` value. (@typescript-eslint/no-unsafe-assignment)

我控制message的内容,所以我想告诉TS,从JSON.parse()出来的实际上是一个对象。我该怎么做呢?

注意:我可以将警告静音,但我想知道是否有更好的方法来处理这个问题。

问题是JSON.parse返回any类型

这很公平——TypeScript不知道它是要解析成一个字符串、一个数字还是一个对象。

你有一个检查规则说'不允许将变量赋值为any'。

可以强制json。parse

的结果
type SomeObjectIKnowAbout = {
}; 
const result = JSON.parse(message.toString()) as SomeObjectIKnowAbout; 

我倾向于在这种情况下做的是创建一个特定的解析函数,它将在运行时断言对象确实是你所说的形状,并将进行类型转换,以便你可以在编写代码时将其视为该对象。

type SomeObjectIKnowAbout = {
userId: string; 
}
type ToStringable = {
toString: () => string; 
}
function parseMessage(message: ToStringable ) : SomeObjectIKnowAbout {
const obj = JSON.parse(message.toString()); //I'm not sure why you are parsing after toStringing tbh. 
if (typeof obj === 'object' && obj.userId && typeof obj.userId === 'string') {
return obj as SomeObjectIKnowAbout; 
}
else {
throw new Error ("message was not a valid SomeObjectIKnowAbout"); 
}
}

JSON.parse不是泛型的,所以我们不能提供一个泛型参数来实现它。

你有几个选择。

简单的事情是,因为JSON.parse返回any,你可以只定义你要分配给它的类型:

let mqttMessage: MQTTMessage = JSON.parse(message.toString());

(我使用MQTTMessage作为适当类型的替代)

但是,对于每个人来说,这可能不是类型安全的,因为它假设字符串定义了您希望它定义的内容。还有一个问题,如果你在其他地方做,你会重复这个假设。 相反,您可以定义一个函数:
function parseMQTTMessageJSON(json: string): MQTTMessage {
const x: object = JSON.parse(json);
if (x && /*...appropriate checks for properties here...*/"someProp" in x) {
return x as MQTTMessage;
}
throw new Error(`Incorrect JSON for 'MQTTMessage' type`);
}

那么你的代码是:

let mqttMessage = parseMQTTMessageJSON(message.toString());

作为类型断言和运行时包装函数的替代方法,您可以利用声明合并来用parse方法的泛型重载来扩展全局JSON对象。这将允许您传递期望的类型,并在解析时使用reviver时提供改进的智能感知:

interface JSON {
parse<T = unknown>(text: string, reviver?: (this: any, key: keyof T & string, value: T[keyof T]) => unknown): T
}
type Test = { a: 1, b: "", c: false };
const { a, b, c } = JSON.parse<Test>(
"{"a":1,"b":"","c":false}",  
//k is "a"|"b"|"c", v is false | "" | 1
(k,v) => v
);

或者,如果您依赖于声明文件来扩展全局接口:

declare global {
interface JSON {
parse<T = unknown>(text: string, reviver?: (this: any, key: keyof T & string, 
value: T[keyof T]) => unknown): T
}
}
游乐场

最新更新