-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Const contexts for literal expressions #29510
Conversation
Did you consider using |
A question: let obj = {
x: 10,
z: { a: { b: 42 } } as const
}; to initialize a type like: let obj: {
x: number;
z: {
readonly a: {
readonly b: 42;
};
};
}; If yes, probably you want to add a test like that. |
This is AWESOME. Thank you @ahejlsberg! |
I did not. Can you provide an example of what you mean exactly?
Yes.
Sure. |
Currently neither of these give excess property errors: const u: { x: number } | { y: string } = { x: 42, y: "helloworld" };
const i: { a: { x: number } & { y: string } } & { b: boolean } = { a: { x: 42, y: "y", z: "excess" }, b: true }; Though these EPC bugs are on the backlog to fix for all literals, there are 2 obstacles:
I'm suggesting that maybe these give errors by using const contexts as a marker to enable complete and correct EPC: const u: { x: number } | { y: string } = { x: 42, y: "helloworld" } as const; // error 'y' is excess (or some better error)
const i: { a: { x: number } & { y: string } } & { b: boolean } = { a: { x: 42, y: "y", z: "excess" }, b: true } as const; // error 'z' is excess Basically using const contexts as a way to trial full-EPC in a way that does not introduce any breaking changes. If the trial is successful then full-EPC can be rolled out to all literals with const being ahead of the curve; if the trail does not work out then full-EPC can be removed in const contexts in a non-breaking way. |
Can it be also assumed in certain situations? Like: const a: 12; // type is 12
let x = {
// Can this be `const`?
// Either always, or only when it's `readonly x1: a`. It's fine either way.
x1: a
}; The situation here being assignment to a constant, and fine to require Also, one important situation (as mentioned with more details): function createAction<TType>(type: TType) {
// Not concerned with return types here, but inferred argument type
return {
type: type
};
}
// Today this gets inferred as string, but can string literal be inferred as itself?
const doStuff = createAction("DO_STUFF"); The situation here being sending a literal (string or number) to a function with argument type being generic and inferred from usage. It'll be nice to avoid |
Next step: allowing |
Is the |
That would require adding a new keyword for dubious benefit. Personally I think |
But it was already a literal, before you added |
be it a |
Question: if the |
to those who believes in |
@ahejlsberg Would there be any way to dynamically concatenate two literal types to produce a new literal type using this For example, in a function like... const concatLiterals = <A extends string, B extends string>(a: A, b: B) =>
`${a}{b}` as const // or (a + b) as const I'm assuming the dynamic nature of the above here would prevent this from working, and it would still widen the type to It would be great to have some sort of type-level concat helper for literals like this.... so that you could do something like: (a + b) as (const: A + B) or `${a}{b}` as (const: ConcatLit<A, B>) or something along those lines. |
Apparently |
I agree with I suspect that we'll end up with a quick fix like |
oh let's not forget what readonly really is #13002 |
Somehow I knew exactly what you linked to before I clicked on it. |
This is probably out of the scope, but: |
+1 for |
Is there a way to allow constant string to represent string literals? For example:
In the case above, "mod" is of type "any" because the compiler doesn't recognize the string literal in the constant
I may also add, it seems very difficult to import namespaces using dynamic imports, which I think is another terrible oversight.
That doesn't even make sense. A namespace, while a type, is still a reference under the hood, and thus should still be importable dynamically somehow; perhaps like:
I think all this would aim to better support dynamic imports "on demand" instead of modules forcibly loading every single module when some may not be needed at all, It could also help promote faster initial page loads in many cases. ;) |
@rjamesnw since this PR is already merged I don't expect that you can get traction for anything new, but this is a good one actually. Can you please open a new issue for it? Thanks. |
You’re right, sorry, it also occurred to me and I was going to get to doing so asap. ;) Update: Issue created: #32401 |
When we want to use other TypeScript version and we do: `npm install [email protected] -D` But when we use new features like const casting microsoft/TypeScript#29510 it does not compile. Instead of that if we use: `yarn add [email protected]` Everything works
This commit refactors the SignatureType enum into an array of strings declared [as const](microsoft/TypeScript#29510). This allows the SignatureType type to be expressed as a union type, which works a bit better when parsing a users provided string. This is some simple refactoring in preparation for declarative function signatures.
This commit refactors the SignatureType enum into an array of strings declared [as const](microsoft/TypeScript#29510). This allows the SignatureType type to be expressed as a union type, which works a bit better when parsing a users provided string. This is some simple refactoring in preparation for declarative function signatures. BREAKING CHANGE: exported SignatureType type is converted from an enum to a union type
This commit refactors the SignatureType enum into an array of strings declared [as const](microsoft/TypeScript#29510). This allows the SignatureType type to be expressed as a union type, which works a bit better when parsing a users provided string. This is some simple refactoring in preparation for declarative function signatures. BREAKING CHANGE: exported SignatureType type is converted from an enum to a union type
Why would someone use let numbers = [1, 2, 3] as const; |
Excuse me,why is the error reported?
|
Because not every element of the array has an |
I found out that let x = 12;
x = 2 as const;
x = 5;
console.log(x); // 5 Also you'll get no error if the reassigned value is like the previous value: let x = [1, 2] as const;
x = [1, 2]; // works |
Is there a way to type an array of objects declared using |
With this PR we introduce
const
assertions which favor immutability in the types inferred for literal expressions (inspired by suggestions in #10195, #20195, and #26979). Aconst
assertion is simply a type assertion that uses the reserved wordconst
as the type name:A
const
assertion establishes a const context in whichConst contexts do not otherwise affect types of expressions, and expressions in const contexts never have a contextual type.
An expression
x
is said to occur in a const context ifx
isconst
assertion, orNote in particular that const contexts extend into nested array and object literals. For example, the declaration
corresponds to
A
const
assertion requires the operand to be a string, number, bigint, boolean, array, or object literal, optionally enclosed in one or more levels of parentheses. It is an error to apply aconst
assertion to expressions of other forms.Fixes #10195.
Fixes #20195.
Fixes #26979.