为推迟的值分配正确键入

  • 本文关键字:分配 推迟 typescript
  • 更新时间 :
  • 英文 :


如何正确地键入从一开始就未定义或为null的变量,但稍后肯定会赋值,并且不使用非null断言";。

非常简化的问题再现:

function example(): number {
let x: null | number = null;
function doStuff(n: number) {
x = n;
} 
if(Math.random() > 0.5) {
doStuff(1);
} else {
doStuff(2);
}
return x;
}

TS游乐场

我的真实案例看起来更像这样:

export function useElection(
id: string | Ref<string>,
): {
loading: Ref<boolean>, 
error: Ref<any>,
election: ComputedRef<Election>,
} {
const fetchCtrl: Ref<ReturnType<FetchElection> | null> = ref(null);
const store = useElectionsStore();
const election: ComputedRef<Election> = computed(
() => store.electionById(unref(id))
);
function doFetch() {
fetchCtrl.value = (store.fetchElection as FetchElection)(unref(id), includingCandidates, autoUpdateInterval);
}
if (isRef(id)) {
watchEffect(doFetch)
} else {
// otherwise, just fetch once
// and avoid the overhead of a watcher
doFetch();
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return {...fetchCtrl.value!, election };
}

这是typescript进行控制流分析(CFA(方式的限制。如上所述,CFA不跨越函数边界,因此在尝试计算类型时不会考虑函数中的赋值。

由于您的实际示例约束了一个包装器对象,因此可以使用自定义类型断言来进行类型检查。

type Ref<T> = { value: T }
function example(): number {
let x: Ref<null | number> = { value : null };
function doStuff(p: Ref<null | number>, n: number): asserts p is Ref<number>{
p.value = n;
} 
if(Math.random() > 0.5) {
doStuff(x, 1);
} else {
doStuff(x, 2);
}
return x.value; // number now
}

游乐场链接

TS实际上并没有检查自定义类型断言实现,所以您要负责实现,所以当您返回时,不确定这是否比简单的类型断言好得多。

最新更新