访问未知对象成员时如何正确修复'no-implicit-any'?
How to properly fix 'no-implicit-any' when accessing unknown object member?
在一个大型项目中,我有一个标准的报告模块,它显示在网格数据中,用户可以在其中定义过滤器和排序。
因为我不想复制逻辑,所以我设置了一个通用过滤函数,它可以接受来自任何类型和过滤选项的数据。
一切正常,但 ESlint 因 any
用法而大喊大叫。
这是一个简化的 reproductible code(实际代码包含更多规则和复杂性,例如字符串规范化和数据排序):
// In module utility
type reportState = {
filterOn : string,
filterValue : string
}
const filterDataPredicate = (row : any, viewOptions : reportState)=>{
const dataKey = viewOptions.filterOn as keyof any;
const valueToCheck = row[dataKey];
return valueToCheck?.toString() === viewOptions.filterValue;
}
// In consuming module 1
type Point = {
x: number,
y: number
};
const graphData: Point[] = [
{ x: 0, y: 20 }, { x: -8, y: 12 }, { x: 100, y: 0 }
]
const currentGraphReportOptions = {
filterOn : "x",
filterValue : "0"
};
const filteredGraphData = graphData.filter((row)=>filterDataPredicate(row, currentGraphReportOptions));
console.log(filteredGraphData);
// In consuming module 2
type Customer = {
firstName: string,
lastName: string
};
const customerData: Customer[] = [
{ firstName: "John", lastName : "Smith"}, { firstName : "Jane", lastName:"Smith"},{ firstName : "Joe", lastName:"Dalton"}
]
const currentCustomerReportOptions = {
filterOn : "lastName",
filterValue : "Smith"
};
const filteredCustomerData = customerData.filter((row)=>filterDataPredicate(row, currentCustomerReportOptions));
console.log(filteredCustomerData);
除 ESLint 警告外,一切正常:
warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
我的 IDE (VSCode) 建议我将类型替换为 unknown
或 never
,但 none 有效。
当使用 unknown
时,row[dataKey]
没有编译(Object is of type 'unknown'.(2571)
),而当使用 never
时,它告诉我 .toString()
在never
类型 (Property 'toString' does not exist on type 'never'.(2339)
).
有没有一种干净的方法来解决这个问题?
PS:如果重要,我在我的 tsconfig.json 文件中启用 strict : true
,并且在我的 eslint 配置中我有:
{
"rules": {
"@typescript-eslint/no-explicit-any": "error"
}
}
您可以将 eslint
规则更改为 "@typescript-eslint/no-explicit-any": "off"
。然后它就不会再抱怨了。如果您希望它警告您但不抛出错误,您也可以将其更改为 warning
。
我设法解决了问题(w/o 禁用规则)
行对象的正确类型应该Record<string, unknown>
。
我认为这是可行的,因为我的传入行将是非空对象,没有其他任何东西(没有基类型,...)。无论对象值是什么,它始终由对象键标识。
// In module utility
type reportState = {
filterOn : string,
filterValue : string
}
const filterDataPredicate = (row : Record<string, unknown>, viewOptions : reportState)=>{
const dataKey = viewOptions.filterOn;
const valueToCheck = row[dataKey];
return `${valueToCheck}` === viewOptions.filterValue;
}
// In consuming module 1
type Point = {
x: number,
y: number
};
const graphData: Point[] = [
{ x: 0, y: 20 }, { x: -8, y: 12 }, { x: 100, y: 0 }
]
const currentGraphReportOptions = {
filterOn : "x",
filterValue : "0"
};
const filteredGraphData = graphData.filter((row)=>filterDataPredicate(row, currentGraphReportOptions));
console.log(filteredGraphData);
// In consuming module 2
type Customer = {
firstName: string,
lastName: string
};
const customerData: Customer[] = [
{ firstName: "John", lastName : "Smith"}, { firstName : "Jane", lastName:"Smith"},{ firstName : "Joe", lastName:"Dalton"}
]
const currentCustomerReportOptions = {
filterOn : "lastName",
filterValue : "Smith"
};
const filteredCustomerData = customerData.filter((row)=>filterDataPredicate(row, currentCustomerReportOptions));
console.log(filteredCustomerData);
在一个大型项目中,我有一个标准的报告模块,它显示在网格数据中,用户可以在其中定义过滤器和排序。
因为我不想复制逻辑,所以我设置了一个通用过滤函数,它可以接受来自任何类型和过滤选项的数据。
一切正常,但 ESlint 因 any
用法而大喊大叫。
这是一个简化的 reproductible code(实际代码包含更多规则和复杂性,例如字符串规范化和数据排序):
// In module utility
type reportState = {
filterOn : string,
filterValue : string
}
const filterDataPredicate = (row : any, viewOptions : reportState)=>{
const dataKey = viewOptions.filterOn as keyof any;
const valueToCheck = row[dataKey];
return valueToCheck?.toString() === viewOptions.filterValue;
}
// In consuming module 1
type Point = {
x: number,
y: number
};
const graphData: Point[] = [
{ x: 0, y: 20 }, { x: -8, y: 12 }, { x: 100, y: 0 }
]
const currentGraphReportOptions = {
filterOn : "x",
filterValue : "0"
};
const filteredGraphData = graphData.filter((row)=>filterDataPredicate(row, currentGraphReportOptions));
console.log(filteredGraphData);
// In consuming module 2
type Customer = {
firstName: string,
lastName: string
};
const customerData: Customer[] = [
{ firstName: "John", lastName : "Smith"}, { firstName : "Jane", lastName:"Smith"},{ firstName : "Joe", lastName:"Dalton"}
]
const currentCustomerReportOptions = {
filterOn : "lastName",
filterValue : "Smith"
};
const filteredCustomerData = customerData.filter((row)=>filterDataPredicate(row, currentCustomerReportOptions));
console.log(filteredCustomerData);
除 ESLint 警告外,一切正常:
warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
我的 IDE (VSCode) 建议我将类型替换为 unknown
或 never
,但 none 有效。
当使用 unknown
时,row[dataKey]
没有编译(Object is of type 'unknown'.(2571)
),而当使用 never
时,它告诉我 .toString()
在never
类型 (Property 'toString' does not exist on type 'never'.(2339)
).
有没有一种干净的方法来解决这个问题?
PS:如果重要,我在我的 tsconfig.json 文件中启用 strict : true
,并且在我的 eslint 配置中我有:
{
"rules": {
"@typescript-eslint/no-explicit-any": "error"
}
}
您可以将 eslint
规则更改为 "@typescript-eslint/no-explicit-any": "off"
。然后它就不会再抱怨了。如果您希望它警告您但不抛出错误,您也可以将其更改为 warning
。
我设法解决了问题(w/o 禁用规则)
行对象的正确类型应该Record<string, unknown>
。
我认为这是可行的,因为我的传入行将是非空对象,没有其他任何东西(没有基类型,...)。无论对象值是什么,它始终由对象键标识。
// In module utility
type reportState = {
filterOn : string,
filterValue : string
}
const filterDataPredicate = (row : Record<string, unknown>, viewOptions : reportState)=>{
const dataKey = viewOptions.filterOn;
const valueToCheck = row[dataKey];
return `${valueToCheck}` === viewOptions.filterValue;
}
// In consuming module 1
type Point = {
x: number,
y: number
};
const graphData: Point[] = [
{ x: 0, y: 20 }, { x: -8, y: 12 }, { x: 100, y: 0 }
]
const currentGraphReportOptions = {
filterOn : "x",
filterValue : "0"
};
const filteredGraphData = graphData.filter((row)=>filterDataPredicate(row, currentGraphReportOptions));
console.log(filteredGraphData);
// In consuming module 2
type Customer = {
firstName: string,
lastName: string
};
const customerData: Customer[] = [
{ firstName: "John", lastName : "Smith"}, { firstName : "Jane", lastName:"Smith"},{ firstName : "Joe", lastName:"Dalton"}
]
const currentCustomerReportOptions = {
filterOn : "lastName",
filterValue : "Smith"
};
const filteredCustomerData = customerData.filter((row)=>filterDataPredicate(row, currentCustomerReportOptions));
console.log(filteredCustomerData);