问题
Angular 8 :
I used to use as a short hack on typescript side :
object['accessor']['accessor']['accessor']
to get
object.accessor.accessor.accessor
without running the risk of throwing an error if one of the children was empty.
What is the best way to do this by today's ECMA Script standards inside the typescript file?
EDIT :
I found this https://medium.com/inside-rimeto/optional-chaining-in-typescript-622c3121f99b
the b/ Nested Ternary Expressions seems the best but it seems convoluted
EDIT 2 :
nevermind, this crashes the application irrecuperably (at the component level, though) just as much.
it seem newer anguar rules are more strict. they just haven't provided an alternative.
回答1:
I prefer the boolean expression approach.
let object = {
accessor: {
accessor: {
accessor: "test"
}
}
}
if (object
&& object.accessor
&& object.accessor.accessor
&& object.accessor.accessor.accessor) {
console.log(object.accessor.accessor.accessor);
} else {
console.log(null);
}
If you don't care about compile time error checking you could do something weird like this. I wouldn't recommend it.
function tryGetValue(obj, propertiesPath) {
if (!obj) {
return null;
}
if (!propertiesPath) {
return obj;
}
let current = obj;
let properties = propertiesPath.split(".");
for (let i = 0; i < properties.length; i++) {
if (current[properties[i]] !== undefined) {
current = current[properties[i]];
} else {
current = null;
break;
}
}
if (current !== undefined) {
return current;
} else {
return null;
}
}
console.log(tryGetValue(object, "accessor.accessor.accessor"));
回答2:
there is an npm package for this named snq(Safe Navigation Query) by armanozak. Very simple and robust solution.
You can use it like this
snq(() => object.accessor.accessor.accessor, anyDefaultValueIfYouLike);
And If you wonder how it is working, here is the source code I copied from github repo
export default function snq<T = any>(callback: () => T, defaultValue?: T) {
try {
const result = callback();
return typeof result === 'undefined' ? defaultValue : result;
} catch (err) {
if (err instanceof TypeError) {
return defaultValue;
}
throw err;
}
}
回答3:
You can simply do the following
// Sample object
const object = {
someKey: 'First Level Value',
accessor: {
someKey: 'Second Level Value',
accessor: {
someKey: 'Third Level Value',
accessor: 'Accessor Value'
}
}
};
// Using ternary expression to do conditional validation check
// Usage --> condition to check ? 'Do this if condition is true' : 'Do this if condition is false'
const accessorValue = object ? // first (?) operator
object.accessor ? // second (?) operator
object.accessor.accessor ? // third (?) operator
object.accessor.accessor ? // fourth (?) operator
object.accessor.accessor.accessor :
null : // to match the first (?) operator
null : // to match the second (?) operator
null : // to match the third (?) operator
null; // to match the fourth (?) operator
console.log(accessorValue); // Accessor Value
回答4:
I like using Ramda's path function in my angular projects.
import * as R from 'ramda';
const leaf = R.path(['accessor', 'accessor', 'accessor'], object);
Another appraoch that I have been using to avoid crash if child is empty (when ramda is not around), comes from inpiration from swifts .?
and ??
operators to default to something if child is empty.
You don't need fancy functions, this single liner will do the trick crash proof
const leaf = (((object || {}).accessor || {}).accessor || {}).accessor;
In action:
const wrongObject = { accessor: null };
const validObject = {
accessor: {
accessor: {
accessor: 'your leaf value'
}
}
};
// crash proof, returning: undefined
const wrongLeaf = (((wrongObject || {}).accessor || {}).accessor || {}).accessor
console.log(wrongLeaf);
// or even with fallback / default value
const defaultLeaf = (((wrongObject || {}).accessor || {}).accessor || {}).accessor || 'default 123';
console.log(defaultLeaf);
const validLeaf = (((validObject || {}).accessor || {}).accessor || {}).accessor
console.log(validLeaf);
回答5:
You could do something like this as a shorthand, which would allow the types to flow through, I assume.
const value = (() => {try{return object.accessor.accessor.accessor}catch(e){return yourDefault;}})();
来源:https://stackoverflow.com/questions/57960362/angular-8-native-typescript-crash-free-accessor-shorthand