I want to implement a set of 3 functions: pair
, head
, tail
that works like this
<code>const p = pair(1, "hello")
const h = head(p) // 1
const t = tail(p) // "hello"
</code>
<code>const p = pair(1, "hello")
const h = head(p) // 1
const t = tail(p) // "hello"
</code>
const p = pair(1, "hello")
const h = head(p) // 1
const t = tail(p) // "hello"
I have 2 implementations:
<code>// version 1: using array data structure
function pair<T1, T2>(a: T1, b: T2) {
const result: [T1, T2] = [a, b]
return result
}
function head<T1, T2>(p: [T1, T2]) {
return p[0]
}
function tail<T1, T2>(p: [T1, T2]) {
return p[1]
}
const p = pair(1, "hello")
const h = head(p) // typescript know h is a number
const t = tail(p) // typescript know t is a string
</code>
<code>// version 1: using array data structure
function pair<T1, T2>(a: T1, b: T2) {
const result: [T1, T2] = [a, b]
return result
}
function head<T1, T2>(p: [T1, T2]) {
return p[0]
}
function tail<T1, T2>(p: [T1, T2]) {
return p[1]
}
const p = pair(1, "hello")
const h = head(p) // typescript know h is a number
const t = tail(p) // typescript know t is a string
</code>
// version 1: using array data structure
function pair<T1, T2>(a: T1, b: T2) {
const result: [T1, T2] = [a, b]
return result
}
function head<T1, T2>(p: [T1, T2]) {
return p[0]
}
function tail<T1, T2>(p: [T1, T2]) {
return p[1]
}
const p = pair(1, "hello")
const h = head(p) // typescript know h is a number
const t = tail(p) // typescript know t is a string
This version works perfectly, typescript know exactly what type of h and t
<code>// version 2: using closures
type Pair<T1, T2> = (n: 1 | 2) => T1 | T2
function pair<T1, T2>(a: T1, b: T2) {
const result: Pair<T1, T2> = (n: 1 | 2) => {
switch (n) {
case 1:
return a
case 2:
return b
}
}
return result
}
function head<T1, T2>(p: Pair<T1, T2>) {
return p(1)
}
function tail<T1, T2>(p: Pair<T1, T2>) {
return p(2)
}
const p = pair(1, 'hello')
const h = head(p) // typescript says h is number | string
const t = tail(p) // typescript says t is number | string
</code>
<code>// version 2: using closures
type Pair<T1, T2> = (n: 1 | 2) => T1 | T2
function pair<T1, T2>(a: T1, b: T2) {
const result: Pair<T1, T2> = (n: 1 | 2) => {
switch (n) {
case 1:
return a
case 2:
return b
}
}
return result
}
function head<T1, T2>(p: Pair<T1, T2>) {
return p(1)
}
function tail<T1, T2>(p: Pair<T1, T2>) {
return p(2)
}
const p = pair(1, 'hello')
const h = head(p) // typescript says h is number | string
const t = tail(p) // typescript says t is number | string
</code>
// version 2: using closures
type Pair<T1, T2> = (n: 1 | 2) => T1 | T2
function pair<T1, T2>(a: T1, b: T2) {
const result: Pair<T1, T2> = (n: 1 | 2) => {
switch (n) {
case 1:
return a
case 2:
return b
}
}
return result
}
function head<T1, T2>(p: Pair<T1, T2>) {
return p(1)
}
function tail<T1, T2>(p: Pair<T1, T2>) {
return p(2)
}
const p = pair(1, 'hello')
const h = head(p) // typescript says h is number | string
const t = tail(p) // typescript says t is number | string
How can I improve the version 2 to make typescript know exactly what type of h and t?