假设我有一些对象可以将 key
作为字符串,将 value
作为 enum
或键和值作为枚举的对象。
类型
export enum ERRORS {
ERROR1 = 'Error1',
ERROR2 = 'Error2',
}
export type ErrorType = 'blue' | 'green';
export interface ErrorByCode {
[key: string]: ERRORS | Record<ErrorType, ERRORS>;
}
代码
const ERRORS_BY_CODE: ErrorByCode = {
default: ERRORS.ERROR1,
'01': ERRORS.ERROR2,
'2': {
blue: ERRORS.ERROR1,
green: ERRORS.ERROR2,
},
};
const errorResolver = ({code, type}: {code: string; type: ERRORS}) => {
const errorMessage =
(ERRORS_BY_CODE?.[code] || ERRORS_BY_CODE?.[code]?.[type]) ??
ERRORS_COMPONENTS_BY_CODE.default;
return errorMessage
};
console.log(errorResolver({code: '01', type: 'blue'}))
但是我在 ERRORS_BY_CODE?.[code]?.[type] 下遇到了 ts 错误
元素隐式具有“any”类型,因为类型“ErrorType”的表达式不能用于索引类型“ERRORS |记录<错误类型,错误>'。
类型“ERRORS_BY_CODE”上不存在属性“blue” |记录
答案 0 :(得分:0)
编译器不希望任何人尝试使用 string
之类的键索引 ERRORS
(即 "blue"
),并且它不允许这样做。它会认为该属性属于 any
类型,并给出编译错误:
function nope(str: string) {
str.blue // error! Property 'blue' does not exist on type 'string'
}
如果一个值的类型是 string
的 union 和其他东西,编译器也会对这样的索引不满意,因为它可能是 string
for它只知道:
function stillNope(uni: string | { blue: number }) {
uni.blue // error! Property 'blue' does not exist on type 'string'
}
Optional chaining 没有解决这个问题。即使您使用 ?.
而不是 .
,也不允许您访问对象的未知属性。这项禁令是有意的;有关详细信息,请参阅 microsoft/TypeScript#33736。
如果要访问联合类型上的属性,其中至少有一个联合成员不知道该属性具有该属性,则需要使用某种其他形式的类型保护。一种方法是使用 typeof
guarding:
function typeofGuard(
uni: ERRORS | { blue: ERRORS, green: ERRORS },
type: ErrorType
) {
const errors = typeof uni === "string" ? uni : uni[type];
}
另一种可能性是将您的联合表示为一个联合,其中联合的每个成员在 ErrorType
键上都有已知的行为。您可以将 ERRORS
设置为 string
,而不是 ErrorType
,后者是在 ERRORS & {[P in ErrorType]?: undefined }
处没有已知行为的 ERRORS
。含义:它是 ErrorType
,如果您使用 undefined
键对其进行索引,您将获得 function exclusiveUnion(
uni: (ERRORS & { [P in ErrorType]?: undefined }) | (Record<ErrorType, ERRORS>),
type: ErrorType
) {
const errors = uni[type]; // ERRORS | undefined
}
属性。这也会使您的错误消失:
$fakeFilesystem = Storage::fake('somediskname');
$proxyMockedFakeFilesystem = Mockery::mock($fakeFilesystem);
$proxyMockedFakeFilesystem->shouldReceive('temporaryUrl')
->andReturn('http://some-signed-url.test');
Storage::set('somediskname', $proxyMockedFakeFilesystem);