TypeScript Version: 3.1.0-dev.201xxxxx
Search Terms:
string as string, cast string as string, cast string as string literal
I am sorry, I have no idea on how to search for it, enlighten me, if you know.
Code
interface Iperiod {
id: number | 'current';
name: string;
}
function usePeriods(periods: Iperiod[]) {
return periods;
}
usePeriods(['now', 'then'].map((name, index) => {
if (name == 'now') {
return {
name,
id: 'current',
}
}
return {
name,
id: index,
}
}));
Expected behavior:
It should work, as id
can be number | 'current'
.
Actual behavior:
Error string is not assignable to 'current'.
Playground Link:
link
Related Issues:
No, but I suppose a few.
If you declares the return type of the lambda it works:
interface Iperiod {
id: number | 'current';
name: string;
}
function usePeriods(periods: Iperiod[]) {
return periods;
}
usePeriods(['now', 'then'].map((name, index): Iperiod => {
if (name == 'now') {
return {
name,
id: 'current',
}
}
return {
name,
id: index,
}
}));
I think is a duplicate.
If I cast it like so it works:
return {
name,
id: 'current' as 'current',
}
, but damn, it feels dumb...
There are actually a few reasons why you should ensure an object literal has a contextual type -- it helps avoid misspelling optional properties and gets you literal types. (See palantir/tslint#2581)
@j-oliveras But the usePeriods
function requires Iperiod[]
, therefor this information should be passed down to the map method return type, don't you think?
Created an issue to improve error reporting here: #26413
Could you please elaborate more on how this helps "avoid misspelling optional properties and gets you literal types"? Perhaps adding example, that says thousands words.
If this should be sometime closed it should bet a proper explanation of what is that big benefit that we have to cast string literal to string literals.
The "it" in that sentence reverse to "has a contextual type", which comes from giving a type annotation to the object. That also prevents you from needing to cast string literals.
interface I {
kind: "a" | "b",
optional?: number
}
declare function f(i: I): void;
// No contextual type
const i0 = { kind: "a" };
f(i0); // fails
const i1 = { kind: "a" as "a", optinal: 3 };
f(i1); // No compile error, but "optional" not specified as intended
f({ kind: "a", optional: 3 }); // Perfect!
f({ kind: "a", optinal: 3 }); // Compiler catches "optinal" spelling error
I still have hard time understanding it. Or at least to me it is almost like
f({ kind: "a", optinal: 3 });
f({ kind: "a" as "a", optinal: 3 });
I don't see why, if the string literal is in returned object is treated differently from one constructed in parameter.
@Akxe the effective question is, let's say you write this
const obj = { kind: "a" };
obj.kind = "b";
Is this code valid?
When you write an expression, TS has to guess what the domain you intended was. We use the same inference for determining how it's legal to use the object both for read and for writes -- obj.kind
is inferred to be string
unless specified otherwise, which means that the assignment of "b"
is legal but that we aren't guaranteeing it's always "a"
(thus the error).
I get that point, but consider this
interface I {
code: 'mapped',
name: string,
}
const a: I[] = ['a', 'b'].map(name => {
return {
code: 'mapped',
name,
}
});
Here the error is definitely unnecessary, as original
will be always of type 'mapped'
.
@Akxe That's a bug: #11152
It is 2 years old... Any info on what it is waiting for? I saw there waiting for proposal, but how to make one, is there a template?
This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.
'something' as 'something'
seems verbose and pointless? TS should simply error if they didn't pass one of the string literals defined. I don't want my users to have to import a certain type they should just be able to pass a string that is type checked
Note: 'something' as const
is a bit less dumb but works the same.
Most helpful comment
Note:
'something' as const
is a bit less dumb but works the same.