JavaScript has object wrappers that let me check if a primitive type's "property" exists, so how do I get TypeScript to work like this too?
P粉797855790
2023-07-28 18:48:38
<p>The return value of XMLValidator.validate is either true or ValidationError (which is not entirely accurate, see my update), and ValidationError has an err attribute. </p>
<pre class="brush:php;toolbar:false;">validate(xmlData: string, options?: validationOptionsOptional): true | ValidationError</pre>
<p>Because JavaScript uses object wrappers to represent boolean primitive values, I can tell if validation was successful by checking if the err attribute exists. </p>
<pre class="brush:php;toolbar:false;">const result = XMLValidator.validate(message)
if (result.err) { // How do I make it work in ts?
console.log(`invalid XML)
} else {
console.log(`XML)
}</pre>
<p>But TypeScript does not allow me to do this, it will report an error: The attribute 'err' does not exist on the "true" type. </p><p>I don't like the idea of checking the return type first because I find it verbose and there's really no definition of the return value type (see my update). How should I write TypeScript code as concisely as possible? </p><p>--- Update ---</p><p>I further checked the code of validator.js. </p><p><br /></p>
<pre class="brush:php;toolbar:false;">const isValid = validateAttributeString(attrStr, options);
if (isValid !== true) {
return getErrorObject(...);
}
...
function getErrorObject(code, message, lineNumber) {
return {
err: {
code: code,
msg: message,
line: lineNumber.line || lineNumber,
col: lineNumber.col,
},
};
}</pre>
<p>So it looks like I can only use if (typeof result == "boolean") here, but I'm hoping there's a "universal" solution to my question. </p>
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:
TypeScript Playground
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.
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.