typescript 打字稿安全导航运算符 ( ?. ) 或 (!.) 和空属性路径
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40238144/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Typescript the safe navigation operator ( ?. ) or (!.) and null property paths
提问by Emerceen
In Angular2 templates safe operator ?.
works, but not in component.ts
using TypeScript 2.0. Also, safe navigation operator (!.) doesn't work.
在 Angular2 模板中,安全运算符?.
有效,但在component.ts
使用 TypeScript 2.0 时无效。此外,安全导航运算符 (!.) 不起作用。
For example...
例如...
This TypeScript
这个打字稿
if (a!.b!.c) { }
compiles to this JavaScript
编译成这个 JavaScript
if (a.b.c) { }
But when I run it, I get the follow error:
但是当我运行它时,我收到以下错误:
Cannot read property 'b' of undefined
无法读取未定义的属性“b”
Is there any alternative to the following?
有没有以下替代方案?
if (a && a.b && a.b.c) { }
采纳答案by Przemek Struciński
Since TypeScript 3.7 was released you can use optional chaining now.
自 TypeScript 3.7 发布以来,您现在可以使用可选链。
Property example:
属性示例:
let x = foo?.bar.baz();
This is equvalent to:
这相当于:
let x = (foo === null || foo === undefined) ?
undefined :
foo.bar.baz();
Moreover you can call:
此外,您可以致电:
Optional Call
可选电话
function(otherFn: (par: string) => void) {
otherFn?.("some value");
}
otherFn will be called only if otherFn won't be equal to null or undefined
仅当 otherFn 不等于 null 或 undefined 时才会调用 otherFn
Usage optional chaining in IF statement
在 IF 语句中使用可选链
This:
这个:
if (someObj && someObj.someProperty) {
// ...
}
can be replaced now with this
现在可以用这个替换
if (someObj?.someProperty) {
// ...
}
Ref. https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html
参考 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html
回答by Aleksey L.
!
is non-null assertion operator(post-fix expression) - it just saying to type checker that you'resure that a
is not null
or undefined
.
!
is non-null assertion operator(post-fix expression) - 它只是告诉类型检查器你确定它a
不是null
or undefined
。
the operation
a!
produces a value of the type ofa
withnull
andundefined
excluded
该操作
a!
产生一个类型为a
withnull
和undefined
exclude 的值
Optional chainingfinally madeit to typescript (3.7)
The optional chaining operator
?.
permits reading the value of a property located deep within a chain of connected objects without having to expressly validate that each reference in the chain is valid. The?.
operator functions similarly to the.
chaining operator, except that instead of causing an error if a reference is nullish (null
orundefined
), the expression short-circuits with a return value ofundefined
. When used with function calls, it returnsundefined
if the given function does not exist.
可选链运算符
?.
允许读取位于连接对象链深处的属性值,而无需明确验证链中的每个引用是否有效。的?.
操作者的功能同样地.
链接操作,不同之处在于代替如果参考是nullish(导致错误null
或undefined
),则表达式短路用的返回值undefined
。当与函数调用一起使用时,undefined
如果给定的函数不存在,则返回。
Syntax:
语法:
obj?.prop // Accessing object's property
obj?.[expr] // Optional chaining with expressions
arr?.[index] // Array item access with optional chaining
func?.(args) // Optional chaining with function calls
Pay attention:
注意:
Optional chaining is not valid on the left-hand side of an assignment
可选链在赋值的左侧无效
const object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
回答by NaN
Update:
更新:
Planned in the scope of 3.7 release
https://github.com/microsoft/TypeScript/issues/33352
计划在 3.7 版本范围内发布
https://github.com/microsoft/TypeScript/issues/33352
You can try to write a custom function like that.
您可以尝试编写这样的自定义函数。
The main advantage of the approach is a type-checking and partial intellisense.
该方法的主要优点是类型检查和部分智能感知。
export function nullSafe<T,
K0 extends keyof T,
K1 extends keyof T[K0],
K2 extends keyof T[K0][K1],
K3 extends keyof T[K0][K1][K2],
K4 extends keyof T[K0][K1][K2][K3],
K5 extends keyof T[K0][K1][K2][K3][K4]>
(obj: T, k0: K0, k1?: K1, k2?: K2, k3?: K3, k4?: K4, k5?: K5) {
let result: any = obj;
const keysCount = arguments.length - 1;
for (var i = 1; i <= keysCount; i++) {
if (result === null || result === undefined) return result;
result = result[arguments[i]];
}
return result;
}
And usage (supports up to 5 parameters and can be extended):
和用法(最多支持5个参数,可以扩展):
nullSafe(a, 'b', 'c');
Example on playground.
操场上的例子。
回答by TiaanM
Another alternative that uses an external library is _.has()from Lodash.
E.g.
例如
_.has(a, 'b.c')
is equal to
等于
(a && a.b && a.b.c)
EDIT: As noted in the comments, you lose out on Typescript's type inference when using this method. E.g. Assuming that one's objects are properly typed, one would get a compilation error with (a && a.b && a.b.z) if z is not defined as a field of object b. But using _.has(a, 'b.z'), one would not get that error.
编辑:如评论中所述,使用此方法时,您会失去 Typescript 的类型推断。例如,假设一个对象的类型正确,如果 z 未定义为对象 b 的字段,则会出现 (a && ab && abz) 的编译错误。但是使用 _.has(a, 'b.z'),就不会得到那个错误。
回答by VitalyB
A new library called ts-optchainprovides this functionality, and unlike lodash' solution, it also keeps your types safe, here is a sample of how it is used (taken from the readme):
一个名为ts-optchain 的新库提供了此功能,与 lodash 的解决方案不同,它还可以确保您的类型安全,以下是它的使用示例(取自自述文件):
import { oc } from 'ts-optchain';
interface I {
a?: string;
b?: {
d?: string;
};
c?: Array<{
u?: {
v?: number;
};
}>;
e?: {
f?: string;
g?: () => string;
};
}
const x: I = {
a: 'hello',
b: {
d: 'world',
},
c: [{ u: { v: -100 } }, { u: { v: 200 } }, {}, { u: { v: -300 } }],
};
// Here are a few examples of deep object traversal using (a) optional chaining vs
// (b) logic expressions. Each of the following pairs are equivalent in
// result. Note how the benefits of optional chaining accrue with
// the depth and complexity of the traversal.
oc(x).a(); // 'hello'
x.a;
oc(x).b.d(); // 'world'
x.b && x.b.d;
oc(x).c[0].u.v(); // -100
x.c && x.c[0] && x.c[0].u && x.c[0].u.v;
oc(x).c[100].u.v(); // undefined
x.c && x.c[100] && x.c[100].u && x.c[100].u.v;
oc(x).c[100].u.v(1234); // 1234
(x.c && x.c[100] && x.c[100].u && x.c[100].u.v) || 1234;
oc(x).e.f(); // undefined
x.e && x.e.f;
oc(x).e.f('optional default value'); // 'optional default value'
(x.e && x.e.f) || 'optional default value';
// NOTE: working with function value types can be risky. Additional run-time
// checks to verify that object types are functions before invocation are advised!
oc(x).e.g(() => 'Yo Yo')(); // 'Yo Yo'
((x.e && x.e.g) || (() => 'Yo Yo'))();
回答by Alec
Building on @Pvl's answer, you can include type safety on your returned value as well if you use overrides:
以@Pvl 的回答为基础,如果您使用覆盖,您也可以在返回值中包含类型安全:
function dig<
T,
K1 extends keyof T
>(obj: T, key1: K1): T[K1];
function dig<
T,
K1 extends keyof T,
K2 extends keyof T[K1]
>(obj: T, key1: K1, key2: K2): T[K1][K2];
function dig<
T,
K1 extends keyof T,
K2 extends keyof T[K1],
K3 extends keyof T[K1][K2]
>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3];
function dig<
T,
K1 extends keyof T,
K2 extends keyof T[K1],
K3 extends keyof T[K1][K2],
K4 extends keyof T[K1][K2][K3]
>(obj: T, key1: K1, key2: K2, key3: K3, key4: K4): T[K1][K2][K3][K4];
function dig<
T,
K1 extends keyof T,
K2 extends keyof T[K1],
K3 extends keyof T[K1][K2],
K4 extends keyof T[K1][K2][K3],
K5 extends keyof T[K1][K2][K3][K4]
>(obj: T, key1: K1, key2: K2, key3: K3, key4: K4, key5: K5): T[K1][K2][K3][K4][K5];
function dig<
T,
K1 extends keyof T,
K2 extends keyof T[K1],
K3 extends keyof T[K1][K2],
K4 extends keyof T[K1][K2][K3],
K5 extends keyof T[K1][K2][K3][K4]
>(obj: T, key1: K1, key2?: K2, key3?: K3, key4?: K4, key5?: K5):
T[K1] |
T[K1][K2] |
T[K1][K2][K3] |
T[K1][K2][K3][K4] |
T[K1][K2][K3][K4][K5] {
let value: any = obj && obj[key1];
if (key2) {
value = value && value[key2];
}
if (key3) {
value = value && value[key3];
}
if (key4) {
value = value && value[key4];
}
if (key5) {
value = value && value[key5];
}
return value;
}
Example on playground.
操场上的例子。