circumspect
ist eine Reihe von Funktionen, die Ihren TypeScript-/JavaScript-Code sicherer machen. Zu diesen Funktionen gehören invariant
, warning
, assertNever
und mehr.
Es gibt viele hilfreiche Funktionen, die Ihren Code sicherer machen können, z. B. invariant
assertNever
. Viele dieser Funktionen sind als separate npm-Pakete verfügbar (z. B. invariant
). Die Installation eines neuen Pakets (und meistens auch des @types
-Gegenstücks) für jede Funktion ist jedoch nicht sehr praktisch. Außerdem exportieren diese Pakete ihre Funktionen im Allgemeinen als Standardexporte, sodass der automatische VSCode-Import mit ihnen nicht gut funktioniert.
Diese Bibliothek vereint die Funktionen, die Ihren Code sicherer machen, an einem einzigen Ort. circumspect
ist eine einzige Abhängigkeit, die sie alle hat. Und der automatische VSCode-Import funktioniert wie erwartet, da alle von circumspect
bereitgestellten Funktionen benannte Exporte sind.
Darüber hinaus ist circumspect
zu 100 % in TypeScript geschrieben, sodass jede Funktion standardmäßig korrekt typisiert ist. Es besteht also keine Notwendigkeit, separate @types
-Pakete zu installieren.
Verwendung von Garn:
yarn add circumspect
Mit npm:
npm install circumspect
invariant
warning
assertNever
nonNull
invariant
invariant ( value : unknown , message ?: string ) : asserts value
value: unknown
ist der Wert, dessen Wahrhaftigkeit wir sicherstellen möchten.
message?: string
ist eine optionale Fehlermeldung, die in den Fehler eingefügt wird, der ausgegeben wird, wenn der übergebene value
falsch ist. Diese benutzerdefinierte Fehlermeldung wird nur in der Entwicklung angezeigt. In der Produktion wird stattdessen ein generischer Fehler angezeigt ( 'Invariant violation'
) und der message
wird ignoriert.
asserts value
was bedeutet, dass die Funktion lediglich die Art des value
einschränkt, um wahr zu sein, und nichts zurückgibt. invariant
stellt sicher, dass der angegebene value
wahr ist. Ist dies nicht der Fall, wird ein Fehler mit der angegebenen message
ausgegeben (nur in der Entwicklung). Diese Funktion schränkt den value
ordnungsgemäß ein, indem sie alle falschen Werte ausschließt (z. B. null
und undefined
).
invariant
sollte immer dann verwendet werden, wenn wir einen Wert haben, der potenziell falsch sein könnte, wir aber davon überzeugt sind, dass der Wert unter bestimmten Umständen wahr sein muss. Das heißt, die Tatsache, dass der Wert wahr ist, ist eine Invariante, und wenn es jemals passiert, dass der Wert falsch ist, wurde die Invariante verletzt und daher muss ein Fehler ausgelöst werden.
Da das message
in der Produktion vollständig ignoriert wird, möchten Sie es in Produktions-Builds möglicherweise vollständig aus Ihrem Code entfernen. Wie das geht, erfahren Sie im Abschnitt „Optimierungen“.
declare const user : User | null | undefined ;
invariant ( user , 'The user is missing!' ) ;
user ; // If we get here, the type is narrowed to `User`
In diesem Beispiel kann das user
möglicherweise null
oder undefined
(also falsch) sein. Wenn das der Fall ist, liegt eine invariante Verletzung vor und die invariant
Funktion löst einen Fehler aus. Andernfalls wird einfach zurückgegeben und wir wissen, dass user
tatsächlich auf ein Benutzerobjekt zeigt.
warning
warning ( value : unknown , message : string ) : void
value: unknown
ist der Wert, den wir überprüfen möchten. Wenn es falsch ist, wird eine Warnung an die Konsole ausgegeben.
message: string
ist die Warnmeldung, die an die Konsole geschrieben wird.
void
die Funktion gibt nichts zurück. warning
gibt eine Warnung mit der angegebenen message
an die Konsole aus, wenn der angegebene value
falsch ist. Die Warnung wird nur in der Entwicklung ausgegeben. In der Produktion hat diese Funktion keine Wirkung.
Es sollte immer dann verwendet werden, wenn wir eine reine Entwicklungswarnung ausgeben möchten, wenn ein Wert falsch ist. Dies soll Entwicklern dabei helfen, die in der Warnmeldung gemeldeten unkritischen Probleme zu beheben.
Da warning
in der Produktion keine Wirkung hat, möchten Sie möglicherweise Aufrufe dieser Funktion in Produktions-Builds vollständig aus Ihrem Code entfernen. Wie das geht, erfahren Sie im Abschnitt „Optimierungen“.
declare const mode : 'auto' | 'default' | 'slow' | 'fast' ;
warning (
mode !== 'auto' ,
'Mode "auto" has been deprecated. Please use "default" instead.' ,
) ;
In diesem Beispiel möchten wir eine Verfallswarnung ausgeben, wenn der mode
'auto'
ist. Dazu müssen wir einen falschen Wert übergeben, deshalb übergeben wir mode !== 'auto'
, was nur dann falsch ist, wenn der mode
'auto'
ist.
In manchen Fällen ist es sinnvoll, false
direkt zu übergeben. Zum Beispiel:
declare const languages : Language [ ] ;
declare const defaultLanguage : Language ;
declare const langName : string ;
let lang = languages . find ( ( { name } ) => name === langName ) ;
if ( ! lang ) {
warning (
false ,
`Language with name " ${ langName } " not found. Falling back to the default language.` ,
) ;
lang = defaultLanguage ;
}
assertNever
assertNever ( value : never ) : never
value: never
ist der Wert, nachdem alle möglichen Union-Typ-Varianten ausgeschöpft wurden. never
was bedeutet, dass die Funktion niemals zurückkehrt; Es gibt lediglich einen Fehler aus, wenn es jemals tatsächlich aufgerufen wird. assertNever
sollte verwendet werden, um sicherzustellen, dass alle Varianten eines Union-Typs ausgeschöpft sind.
Wenn alle Union-Varianten von value
ausgeschöpft sind, gibt es beim Aufruf von assertNever
mit value
keinen Compilerfehler, da value
zu diesem Zeitpunkt als vom Typ „ never
betrachtet wird und wir zur Laufzeit nie den Punkt erreichen, an dem assertNever
aufgerufen wird, was bedeutet, dass Es wird kein Fehler ausgegeben.
Wenn jedoch nicht alle Union-Varianten ausgeschöpft sind, rufen wir assertNever
mit etwas anderem als never
auf und es kommt zu einem Compilerfehler, der etwa Folgendes sagt:
Argument of type 'x' is not assignable to parameter of type 'never'.
was wir beheben können, indem wir die fehlenden Varianten behandeln. Weitere Informationen zur Überprüfung der Union-Erschöpfung und assertNever
finden Sie in den TypeScript-Dokumenten.
declare const state : 'loading' | 'done' | 'error' ;
switch ( state ) {
case 'loading' :
return < Loading / > ;
case 'done' :
return < Done / > ;
case 'error' :
return < Error / > ;
}
In diesem Beispiel behandeln wir alle möglichen Zustände innerhalb der switch
-Anweisung: 'loading'
, 'done'
und 'error'
.
Was aber, wenn wir in Zukunft einen weiteren Status hinzufügen, beispielsweise 'pending'
?
Die Tatsache, dass die switch
-Anweisung 'pending'
nicht verarbeitet, würde unentdeckt bleiben.
Die Lösung besteht darin, einen default
zu haben, in dem wir behaupten, dass alle möglichen Zustände behandelt wurden.
switch ( state ) {
...
default :
return assertNever ( state ) ;
}
Wenn also alle Zustandsvarianten verarbeitet werden, erhalten wir keinen Fehler bei der Kompilierung. Wenn wir jedoch den neuen Status 'pending'
hinzufügen, erhalten wir eine Compiler-Fehlermeldung:
Argument of type 'string' is not assignable to parameter of type 'never'.
Wir können diesen Fehler beheben, indem wir den Status 'pending'
im switch
behandeln.
Wie Sie diesem Beispiel entnehmen können, ist assertNever
besonders nützlich in switch
-Anweisungen, bei denen wir sicherstellen möchten, dass jederzeit alle möglichen Fälle behandelt werden.
nonNull
nonNull < T > ( value : T | null | undefined ) : value is T
value: T | null | undefined
ist der Wert, den wir überprüfen möchten, um festzustellen, ob er nicht null
oder undefined
ist. value is T
was bedeutet, dass die Funktion einen booleschen Wert zurückgibt, der angibt, ob der übergebene Wert weder null
noch undefined
ist. Dies schränkt den value
auf T
ein (d. h. schließt null
und undefined
aus), wenn true
zurückgegeben wird. nonNull
ist eine Prädikatfunktion, die prüft, ob der angegebene Wert ungleich Null ist, also weder null
noch undefined
. Nach dem Aufruf der Funktion wird der value
ordnungsgemäß eingegrenzt, je nachdem, ob true
oder false
zurückgegeben wurde.
nonNull
sollte immer dann verwendet werden, wenn wir einen Wert haben, der möglicherweise null
, undefined
oder beides sein könnte, und wir dies überprüfen und seinen Typ ordnungsgemäß eingrenzen möchten.
Der Name dieser Funktion leitet sich vom Dienstprogrammtyp NonNullable
ab, der null
und undefined
von einem Typ ausschließt.
declare const names : ( string | null ) [ ] ;
const nonNullNames = names . filter ( nonNull ) ;
// nonNullNames has type 'string[]'
In diesem Beispiel haben wir ein Array von Namen, das auch einige null
enthalten kann. Wir filtern das Array nach allen Nicht-Null-Elementen und erhalten einen string[]
zurück.
Wenn wir stattdessen names.filter(x => x !== null)
verwenden würden, würden wir Nicht-Null-Elemente zurückbekommen, aber der Typ wäre immer noch (string | null)[]
da TypeScript die Funktion sieht, die wir an filter
übergeben da nur ein boolean
zurückgegeben wird und es daher zu keiner Typeingrenzung kommt.
Wir empfehlen die Verwendung von babel-plugin-dev-expression
um das an invariant
übergebene message
zu entfernen und Aufrufe von warning
in der Produktion vollständig zu entfernen.
Grundsätzlich wird in der Produktion babel-plugin-dev-expression
ersetzt
invariant ( value , 'Value is falsy!' ) ;
mit
if ( ! value ) {
invariant ( false ) ;
}
Daher wird das message
entfernt. Außerdem werden Aufrufe von warning
vollständig entfernt. Also Zeilen wie diese
warning ( value , 'Value is falsy!' ) ;
werden entfernt.
Pull-Requests sind herzlich willkommen. Wenn Sie beabsichtigen, eine größere Änderung einzuführen, öffnen Sie bitte zunächst ein entsprechendes Problem, in dem wir besprechen können, was Sie ändern möchten.
Bitte stellen Sie sicher, dass Sie die Tests und die README-Datei entsprechend aktualisieren.
MIT