Typescript 可分配给未标记默认值的标记类
我有一个用于错误的类,它可能有也可能没有一些标记来识别出错的地方(字符串)。我认为如果在签名中可以看到潜在值,这将非常有用,例如:Typescript 可分配给未标记默认值的标记类,typescript,Typescript,我有一个用于错误的类,它可能有也可能没有一些标记来识别出错的地方(字符串)。我认为如果在签名中可以看到潜在值,这将非常有用,例如: function f(): 'success' | MyError<'invalid'|'timeout'> 这种方法有两个问题: 任何消费者都可以访问a.info,即使它不是有用的 构造函数需要一个参数,即使它是一个没有更多信息的错误 第一个问题可以通过在顶部补上一个额外的类型来解决: type InfoError<T extends My
function f(): 'success' | MyError<'invalid'|'timeout'>
这种方法有两个问题:
- 任何消费者都可以访问
,即使它不是有用的a.info
- 构造函数需要一个参数,即使它是一个没有更多信息的错误
type InfoError<T extends MyError> = string extends T['info'] ? Omit<T, 'info'> : T;
let b = new MyError<'something'>('something');
let c: InfoError<MyError> = b;
这里的方法是将一个完全没有标记的错误视为完全不同的类型
类标记错误{
构造函数(公共信息:T){}
}
类未分类错误{
构造函数(/*其他未标记的错误参数?*/){}
}
类型MyError=TaggedError | UntaggedError;
现在MyError
包含了错误实际上可能未标记的可能性。Typescript将在此处保护您,在您确定错误是标记的还是未标记的之前,它不会让您访问info
属性
函数f():“成功”| MyError;
const result=f();
如果(结果==“成功”){
//…成功!
}
//错误:类型UntagedError上不存在属性信息
console.log(result.info);
如果(结果中的“信息”){
log(`TaggedError`);
}否则{
log('untagederror…我不知道发生了什么!');
}
如果您不喜欢结果中的“info”
类型缩小形式,您可以编写一个typeguard
函数IStageDerror(e:MyError):e是TaggedError{
在e中返回“info”;
}
如果(isTaggedError(result)){//类型推断在这里有效
log(`TaggedError`);
}
谢谢,但有一点是,消费者从签名中知道他得到了什么。必须测试,info
存在,而签名已经表明它存在,这有点奇怪。可能是类型MyError=string扩展了T?untagederror:TaggedError会更好,但我也可以使用省略
,但这里有一个奇怪的可分配性问题我无法解决。此外,所有内容都需要显式键入,我不能只返回new MyError()代码>并让推断者处理其余的问题。我理解您的担忧,我认为每个问题都是可以解决的。即使您将info
保留为可选值或为其提供一个虚拟值,您的消费者仍然必须确定他们是否应该关注信息。但是,如果您拆分了这些类型,现在它们有了一种类型安全的、确定的方法来确定是否有任何额外的信息可以从错误中获得。此外,您不会失去任何明确性,因为在本例中,MyError
不再具有构造函数。您必须显式返回一个TaggedError
或UntaggedError
。我接受这一点,因为它一直在正确地推动我,使我不必强制尝试统一类。这就是说,重要的部分是,TaggedError
应该继承自UntaggedError
,因此赋值声明让a:TaggedError;让b:UntagedError=a
保证工作。我得出的结论是,某种统一类型(例如,MyType
)只会让事情变得更加乏味。我忘了基本的东西。我还想在问题中加入我最后一次用暴力强迫的尝试,我认为这是可行的,但是哇,这有点乱。
type InfoError<T extends MyError> = string extends T['info'] ? Omit<T, 'info'> : T;
let b = new MyError<'something'>('something');
let c: InfoError<MyError> = b;