P粉9577231242023-07-29 09:49:07
You're right, TypeScript doesn't allow you to access properties that it doesn't know may exist on the variable type. If the type is a union type, the property must exist on all members of the union type before TypeScript allows you to access it.
But you can reduce the type of variables through various methods. For example, you could first check if the value is true, and if not, TypeScript will narrow the union type down to just a ValidationError.
Usually, another option is to use the in operator, but in this case, the union type contains more than just object types, so TypeScript does not allow it.
You could also define a custom type guard (or use the one provided by the library, if one exists), but for this simple case it seems like that might be the amount of work you want A bit too big.
There are other ways to minify types, as the TypeScript documentation I provided details. As you mentioned, checking the result of the typeof operator is also one of the methods.
This example only declares that a type guard exists, rather than implementing one, but here is how you can use each method to narrow the result variable type:
declare type ValidationError = { err: unknown }; declare function isValidationError(val: unknown): val is ValidationError; declare const XMLValidator: { validate(message: unknown): true | ValidationError }; const message = 'test message'; const result = XMLValidator.validate(message) // You can check first if the result is `true` if (result === true) { // Handle success } else { // Then the `else` branch knows it much be a `ValidationError` console.error(result.err); } // Normally allowed, but not in this case. Error: // Type 'true | ValidationError' is not assignable to type 'object' if ('err' in result) { console.error(result.err) } if (isValidationError(result)) { console.error(result.err); }
Although they are generally best avoided, you can also use TypeScript's as keyword to make type assertions.
The reason it's best to avoid using these type assertions is because you're telling TypeScript to treat one type as another type. Therefore, by doing this, you may be sacrificing type safety.
console.error((result as ValidationError).err);
However, in cases where you understand the situation better than the TypeScript compiler does, this is a tool you can use to provide it with more information.
Personally, I find it helpful to always leave a comment explaining why a type assertion was used, mentioning any assumptions on which its safety is based.
Also, in this case, using a type assertion to check the property will not narrow the type of the result variable, so this approach may not exactly fit your needs.