I don't know if this is possible but it would be a nice addition:
````ts
interface Shape {
b1: number;
b2?: number;
b3?: number;
}
type shapeKind = "triangle" | "rectanle" | "square";
let shapeKindEnum = {
triangle: "triangle",
rectanle: "rectanle",
square: "square"
}
function shapeFactory(kind: shapeKind): Shape {
switch (kind) {
case shapeKindEnum.rectanle:
return { b1: 5 };
case shapeKindEnum.rectanle:
return { b1: 5, b2: 10 };
case shapeKindEnum.rectanle:
return { b1: 5, b2: 6, b3: 10 };
default:
throw new Error("Invalid Shape Kind");
}
}
let triangle1 = shapeFactory("triangle"); // OK
let triangle2 = shapeFactory(shapeKindEnum.rectanle); // Error
````
I understand that this error is caused by shapeKindEnum.rectanle being inferred as a string (which I think is correct) but I wouldn't expect it to fail when is passed to shapeFactory.
I can solve it using:
let shapeKindEnum = {
triangle: <shapeKind>"triangle",
rectanle: <shapeKind>"rectanle",
square: <shapeKind>"square"
}
Could mapped types be used here to avoid casting every single property?
Thanks!
You need to firstly remove the return type annotation from the function. You are specifically saying that you want a less specific type, one that does not contain the literal field, from what you are returning. There are number of other problems with this code so I would suggest that you look at an example of using literal types.
I don't see how the return type of the function could affect the function arguments as being invalid. The following example doesn't have return type annotations and it still throws the same error:
Argument of type 'string' is not assignable to parameter of type 'Size'
type Size = "L" | "M" | "S";
let sizeEnum = {
L: "L",
M: "M",
S: "S"
};
function shapeFactory(size: Size) {
switch (size) {
case sizeEnum.L:
return { b1: 10, b2: 10 };
case sizeEnum.M:
return { b1: 5, b2: 5 };
case sizeEnum.S:
return { b1: 1, b2: 1 };
default:
throw new Error("Invalid Shape Kind");
}
}
let largeBox1 = shapeFactory("L"); // OK
let largeBox2 = shapeFactory(sizeEnum.L); // Argument of type 'string' is not assignable to parameter of type 'Size'
I think this use case is valid when you want to use string enumerations instead of numeric enumerations. I don't want to use "L" all around my code I need an enum or constant to reduce the size of my bundler.
const L: Size = "L";
let largeBox2 = shapeFactory(L); // OK
const L = "L";
let largeBox2 = shapeFactory(L); // Error (Would be nice if ': Size' annotation was not required)
I believe this is what you are looking for:
type Size = "L" | "M" | "S";
let sizeEnum: { [key in Size]: key } = {
L: "L",
M: "M",
S: "S"
};
function shapeFactory(size: Size) {
switch (size) {
case sizeEnum.L:
return { b1: 10, b2: 10 };
case sizeEnum.M:
return { b1: 5, b2: 5 };
case sizeEnum.S:
return { b1: 1, b2: 1 };
default:
throw new Error("Invalid Shape Kind");
}
}
let largeBox1 = shapeFactory("L"); // OK
let largeBox2 = shapeFactory(sizeEnum.L); // OK: sizeEnum.L has type "L"
BTW: the following works with my typescript build (nightly). If you are using let or var then the inferred type is widened to string because the variable is mutable.
let L2 = "L"; // has type `string`
const L = "L"; // has type `"L"`
let largeBox2 = shapeFactory(L);
@gcnew AWESOME :sunglasses: thanks a lot!
Hi @gcnew which version did you use the example you provided doesn't seem to work for me with 2.1.1
I'm currently using Version 2.2.0-dev.20161129 and it works fine. Basically typescript@next
Yes, I just tried typescript@rc and it doesn't work. In @next its fine though.
Most helpful comment
I believe this is what you are looking for:
BTW: the following works with my typescript build (nightly). If you are using
letorvarthen the inferred type is widened tostringbecause the variable is mutable.