Typescript -用一个元组实现Either来处理错误



是否有可能组成一个表示返回错误或值的元组的类型?

async function createUser(userData): Promise<Either<User, UserError>> {}
// This should return a tuple where we have either an user or an error. Not both, not none
const [ user, userError ] = await createUser({ ... })
// Checking if there is an error
if (userError) {
...
// This line represents an early bail, could be throw or return
throw userError
}
// Since we check the error above, this should now be safe to use
console.log(user.name)

您可以创建这样的类型:

type Either<A, B> = [A, undefined?] | [undefined, B];

它将被TypeScript的控制流分析以你想要的方式处理:

TS操场

type Either<A, B> = [A, undefined?] | [undefined, B];
type User = { name: string };
class UserError extends Error {
override name = 'UserError';
}
declare function createUser(userData: User): Promise<Either<User, UserError>>;
const [ user, userError ] = await createUser({name: 'foo'});
user; // User | undefined
userError; // UserError | undefined
if (userError) {
userError; // UserError
throw userError;
}
user; // User
user.name; // string

然而,我更喜欢使用联合来避免额外的元组和变量(受Rust的Result类型的启发):

TS操场

type Result <T = void, E extends Error = Error> = T | E;
function isError <T>(value: T): value is T & Error {
return value instanceof Error;
}
type User = { name: string };
class UserError extends Error {
override name = 'UserError';
}
declare function createUser(userData: User): Promise<Result<User, UserError>>;
const user = await createUser({name: 'foo'});
user; // User | UserError
if (isError(user)) {
user; // UserError
// ... do something else
throw user;
}
user; // User
user.name; // string

最新更新