I'm trying to define a function that returns an object mapping properties (strings) to a lists of strings, except when there's only one item in the list, then I want to map to the string.
type MyType = { [key: string]: string | string[] }
export function myFunc(s: string): MyType {
const result: MyType = {}
for (const param of s.split('&')) {
const [key, val] = param.split(/=(.*)/s, 2)
if (Object.prototype.hasOwnProperty.call(result, key)) {
result[key].push(val ? val : '') // Type error happens here because there's no string.push()
} else {
result[key] = [val ? val : '']
}
}
for (const [key, val] of Object.entries(result)) {
if (val.length === 1) {
result[key] = val[0]
}
}
return result
}
What's the right thing to do here? I could move the first for
loop into its own function that that returns { [key: string]: string[] }
and then do result: MyType = thatFunction()
or I can have two variables
const _result: { [key: string]: string[] } = {}
// [do the first for loop]
const result = _result as MyType
// [do the second for loop]
return result
Is there a way to do this type of stuff, where I want to write something as a given type in my code, then immediately transform that value into a stricter/looser type without an intermediate variable name?
CodePudding user response:
Well, there is a limitation narrowing down the type with bracket notation. But there is a workaround for that which is to assign that property to a temp variable type check it and then assign it :
const temp = result[key];
if (Array.isArray(temp)) { // you need to narrow down the type
temp.push(val ? val : '')
}
if (Array.isArray(result[key])) { // sadly this won't work
result[key].push(val ? val : '')
}
Edit
As your code flow guarantees that result[key]
is always an array. You can safely assert that is an array with a cast like this :
( result[key] as string[]).push(val ? val : '')