2016-09-30 28 views
1

节点回调看起来像:是否可以进行类型安全的节点式回调?

interface NodeCallback<TResult,TError> { 
    (err: TError): void; 
    (err: null, res: TResult): void; 
} 

因此回调将要么得到errres但不能同时。我看到的大多数类型都有errres的硬编码类型为非可选版本。

function readdir(path: string, callback?: (err: NodeJS.ErrnoException, files: string[]) => void): void; 

这不是严格的类型安全。例如,这编译罚款:

fs.readdir('/', (err, files) => { 
    if (err !== null) { // There's an error! 
    files.forEach(log); // Still using the result just fine. 
    } 
}) 

可以使这更(好,那种)安全通过更改签名,包括所有可能的值。

function readdir(path: string, callback?: (err: null | NodeJS.ErrnoException, files?: string[]) => void): void; 

但是没有办法指定之间的依赖两个,所以你需要键入断言res安静下来strictNullChecks

fs.readdir('/', (err, files) => { 
    if (err === null) { // There's no error 
    // files.forEach(log); // Won't compile 
    (files as string[]).forEach(log); // Type assertion 
    files!.forEach(log); // Nice shorthand 
    if (files !== undefined) { // Type guard 
     files.forEach(log); 
    } 
    } 
}) 

这是不是太糟糕,除了:

  • 当你需要反复做。
  • 当你不访问一个属性,所以你键入断言,这可能意味着你需要导入另一种类型。真的很烦人。类型警卫将避免这种情况,但是这会导致不必要的运行时间损失。
  • 它仍然不是安全的。它更加面对你,所以你不得不考虑它,但我们主要依靠手动断言。

如果你真的想你可以用Result样区分联合做到这一点:

type Result<R,E> 
    = { error: false, value: R } 
    | { error: true, value: E } 

function myFunction(callback: (res: Result<string, Error>) => void) { 
    if (Math.random() > 0.5) { 
    callback({ error: true, value: new Error('error!') }); 
    } else { 
    callback({ error: false, value: 'ok!' }) 
    } 
} 

myFunction((res) => { 
    if (res.error) { 
    // type of res.value is narrowed to Error 
    } else { 
    // type of res.value is narrowed to string 
    } 
}) 

这最终是相当不错的诚实,但是这是一个很大的样板,完全违背公共节点样式。

所以我的问题是打字机目前有办法让这种超级常见的模式既安全又方便?我很确定现在的答案是不正确的,这并不是什么大问题,但我只是好奇。

谢谢!

回答

3

唯一的好模式我已经看到了,比你做什么其他的,看起来是这样的:

function isOK<T>(err: Error | null, value: T | undefined): value is T { 
    return !err; 
} 

declare function readdir(path: string, callback: (err: null | Error, files: string[] | undefined) => void): void; 

readdir('foo', (err, files) => { 
    if (isOK(err, files)) { 
     files.slice(0); 
    } else { 
     // need to err! here but 'files' is 'undefined' 
     console.log(err!.message); 
    } 
}) 
+0

我想尽可能多的,虽然我不知道用户定义类型警卫没有。你也是男人! –

相关问题