Is it possible to mark a variable such that it will only be used once?

Won*_*Hau 6 typescript

Consider the following code:

const a = initialValue()
const b = f(a)
const c = g(b)
Run Code Online (Sandbox Code Playgroud)

I want to do something such that when a is being referenced the second time, it will be a compile error.

const d = h(a) // Compile error: `a` can be only referenced once
Run Code Online (Sandbox Code Playgroud)

I need this to prevent faulty value derivation from variables that I'm not supposed to use anymore.

Thus, I'm wondering if this is possible in TypeScript (during compile-time)? If not are there any alternatives that I can consider?

Extra nodes: the main reason I need this feature is to breakdown a very long value derivation process to improve code readability.

Imagine the value derivation is something like this:

const finalValue = q(w(e(r(t(y(u(i(o(p(a(s(d(f(g(h(j(k)))))))))))))))))))
Run Code Online (Sandbox Code Playgroud)

It's obviously necessary to break it down into several sections, that's why I need temporary variables that should be only use once within the same scope.

Edit: Added a realistic example

type Point = {x: number, y: number}
const distance = (a: Point, b: Point): number => {
  return Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2))
}
Run Code Online (Sandbox Code Playgroud)

Obviously the distance function above is not too readable, so I break it down by introducing temporary variable.

const distance = (a: Point, b: Point): number => {
  const xDistance = Math.pow(a.x - b.x, 2)
  const yDistance = Math.pow(a.y - b.y, 2)
  return Math.sqrt(xDistance + yDistance)
}
Run Code Online (Sandbox Code Playgroud)

But then I have another problem, I don't these variables to be used more than once, in this case xDistance and yDistance. Referencing them more than once will introduce bug.

For example, referencing xDistance more than once introduces logical error which cannot be detected by type checking:

const distance = (a: Point, b: Point): number => {
  const xDistance = Math.pow(a.x - b.x, 2)
  const yDistance = Math.pow(a.y - b.y, 2)
  return Math.sqrt(
    xDistance + 
    xDistance // should be `yDistance` 
  ) 
}
Run Code Online (Sandbox Code Playgroud)

for*_*d04 4

我会推荐某种pipe以可读的方式编写函数的方法:

increment(increment(multiply(2)(toLength("foo")))) // 8
Run Code Online (Sandbox Code Playgroud)

变成

flow(
  toLength,
  multiply(2),
  increment,
  increment
)("foo") // 8
Run Code Online (Sandbox Code Playgroud)

正如@Bart Hofland 所说,这将防止临时变量,同时保持代码干净。

Playground 示例
(这是fp-tsflow库的实现)


如果您确实(确实)需要对“一次性”变量进行编译时检查之类的操作:
type UsedFlag = { __used__: symbol } // create a branded/nominal type 
type AssertNotUsed<T> = T extends UsedFlag ? "can be only referenced once" : T

const a = 42 // a has type 42
const b = f(a)
markAsUsed(a)
a // now type (42 & UsedFlag)
const d = h(a) // error: '42 & UsedFlag' is not assignable '"can be only referenced once"'.

function markAsUsed<T>(t: T): asserts t is T & UsedFlag {
    // ... nothing to do here (-:
}

function f(a: number) { }
function h<T>(a: AssertNotUsed<T>) { }
Run Code Online (Sandbox Code Playgroud)

游乐场样本