如何提示我无法控制的函数类型?
How to hint the type of a function I do not control?
解析 JSON 格式的字符串时出现 linter 错误:
let mqttMessage = JSON.parse(message.toString())
// ESLint: Unsafe assignment of an `any` value. (@typescript-eslint/no-unsafe-assignment)
我控制message
的内容所以我想告诉TS,JSON.parse()
出来的其实是一个Object。我该怎么做?
注意:我可以关闭警告,但我想了解是否有更好的方法来解决这个问题。
JSON.parse
不是通用的,因此我们无法提供通用参数来执行此操作。
你有几个选择。
简单的事情是,因为 JSON.parse
returns 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());
问题是 JSON.parse
returns 一个 any
类型。
这很公平 - TypeScript 不知道它是要解析为字符串、数字还是对象。
您有一个 linting 规则说 'Don't allow assigning variables as any'。
所以是的,您可以强制执行 JSON.parse
的结果
type SomeObjectIKnowAbout = {
};
const result = JSON.parse(message.toString()) as SomeObjectIKnowAbout;
在这种情况下,我喜欢做的是创建一个特定的解析函数,它将在运行时断言 obj 确实是您所说的形状,并将进行类型转换,以便您可以同时处理它您正在将代码编写为该对象。
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");
}
}
作为类型断言和运行时包装函数的替代方法,您可以利用 declaration merging 为全局 JSON
对象增加 parse
方法的通用重载。这将允许您通过预期的类型并为您提供改进的 IntelliSense,以防您在解析时使用 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
);
或者,如果您依赖 declaration files 来扩充全局接口:
declare global {
interface JSON {
parse<T = unknown>(text: string, reviver?: (this: any, key: keyof T & string,
value: T[keyof T]) => unknown): T
}
}
解析 JSON 格式的字符串时出现 linter 错误:
let mqttMessage = JSON.parse(message.toString())
// ESLint: Unsafe assignment of an `any` value. (@typescript-eslint/no-unsafe-assignment)
我控制message
的内容所以我想告诉TS,JSON.parse()
出来的其实是一个Object。我该怎么做?
注意:我可以关闭警告,但我想了解是否有更好的方法来解决这个问题。
JSON.parse
不是通用的,因此我们无法提供通用参数来执行此操作。
你有几个选择。
简单的事情是,因为 JSON.parse
returns 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());
问题是 JSON.parse
returns 一个 any
类型。
这很公平 - TypeScript 不知道它是要解析为字符串、数字还是对象。
您有一个 linting 规则说 'Don't allow assigning variables as any'。
所以是的,您可以强制执行 JSON.parse
的结果type SomeObjectIKnowAbout = {
};
const result = JSON.parse(message.toString()) as SomeObjectIKnowAbout;
在这种情况下,我喜欢做的是创建一个特定的解析函数,它将在运行时断言 obj 确实是您所说的形状,并将进行类型转换,以便您可以同时处理它您正在将代码编写为该对象。
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");
}
}
作为类型断言和运行时包装函数的替代方法,您可以利用 declaration merging 为全局 JSON
对象增加 parse
方法的通用重载。这将允许您通过预期的类型并为您提供改进的 IntelliSense,以防您在解析时使用 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
);
或者,如果您依赖 declaration files 来扩充全局接口:
declare global {
interface JSON {
parse<T = unknown>(text: string, reviver?: (this: any, key: keyof T & string,
value: T[keyof T]) => unknown): T
}
}