Description
I have two similar types that are not identical:
type A = {
a?: number
b?: string
c?: boolean
}
type B = {
a?: number
b?: string
c?: string
}
I am looking to create an adapter function f()
that can convert type A to type B, with the condition that only properties populated in A should populate B.
function f(a: A): B
One possible approach is using a for loop:
function f(a: A): B {
const b: B = {}
for (const key of Object.keys(a) as Array<keyof A>) {
if (key === 'c') {
b.c = String(a[key])
} else {
b[key] = a[key] // ❌ Type 'string | number | undefined' is not assignable to type 'undefined'.
}
}
return b
}
The above code seems to be working and logically type safe. TypeScript might not fully grasp its type safety, prompting further exploration on how to make it better understand the types involved.
What I've tried
- Conditional branching based on value type:
function g(a: A): B {
const b: B = {}
for (const key of Object.keys(a) as Array<keyof A>) {
if (key === 'c') {
b.c = String(a[key])
} else if (key === 'a') {
// Handle numbers
b[key] = a[key]
} else {
// Handle strings
b[key] = a[key]
}
}
return b
}
However, this approach leads to duplicate code in multiple branches and could violate the open-closed principle when updating keys or values.
- Using object spreading:
While efficient, concerns arise about creating multiple objects just to spread them into another. Surely there must be a simpler and more streamlined solution to achieve the desired outcome?