2016-09-30 4 views
1

Knoten Rückrufe in etwa so aussehen:Ist es möglich, typensichere Knoten-ähnliche Callbacks zu erstellen?

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

So der Rückruf entweder err oder res aber nicht beide erhalten. Die meisten der Typen, die ich sehe, haben die Typen err und res, die in ihren nicht-optionalen Versionen fest codiert sind.

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

Dies ist nicht streng typsicher. Zum Beispiel diese kompiliert fein:

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

Sie können diese mehr machen (na ja, Art) sicher durch die Unterschrift Ändern aller möglichen Werte aufzunehmen.

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

Aber es gibt keine Möglichkeit, die Abhängigkeit zwischen den beiden so müssen angeben, Sie zu geben res behaupten strictNullChecks zu beruhigen.

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); 
    } 
    } 
}) 

Das ist nicht so schlecht, außer für:

  • Wenn Sie es immer wieder tun müssen, um.
  • Wenn Sie nicht auf eine Eigenschaft zugreifen, so haben Sie zu Assert, was bedeuten könnte, dass Sie einen anderen Typ importieren müssen. Wirklich nervig. Typ-Wächter werden dies vermeiden, aber dann haben Sie eine unnötige Laufzeitstrafe.
  • Es ist immer noch nicht wirklich sicher. Es ist mehr in-your-Face, so dass Sie gezwungen sind, darüber nachzudenken, aber wir verlassen uns hauptsächlich auf manuell zu behaupten.

Wenn Sie wollte wirklich Sie dies mit einem Result -ähnlichen diskriminiert Union tun könnte:

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 
    } 
}) 

Welche ziemlich nett ehrlich zu sein endet, aber das ist eine Menge von vorformulierten und geht völlig gegen gemeinsame Knoten Stil.

Also meine Frage ist, hat Typoskript derzeit eine Möglichkeit, dieses super gemeinsame Muster sowohl typsicher als auch bequem zu machen? Ich bin mir ziemlich sicher, dass die Antwort jetzt nicht stimmt, und das ist keine große Sache, aber ich war nur neugierig.

Danke!

Antwort

3

Die einzige gute Muster, das ich gesehen habe, andere als das, was Sie getan haben, sieht wie folgt aus:

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

ich so viel dachte, obwohl ich nicht über benutzerdefinierte Typ Wachen nicht kannte. Du bist auch der Mann! –

Verwandte Themen