-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
No type error on length-mutating methods with readonly length #56685
Comments
Based on what? Your type clearly states it has such a method. The existence of a read-only |
The Relatedly, making a |
But that's an implementation detail of your method. The type system is completely unaware of this. Besides that, using a type assertion
Writing I don't see anything wrong with this behavior. |
The ECMAScript spec has a note:
It’s not merely an implementation detail - it’s a feature of the |
TypeScript doesn't know what const foo: { readonly foo: string } = { foo: "bar" };
fooey(foo); // no error
console.log(foo.foo); // prints "qux"
function fooey(foo: { foo: string }) {
foo.foo = "qux";
}
|
The absence of a method is unfortunately different from saying that calling the method is illegal. For instance, it can be implicitly re-introduced by narrowing: let x = [] as readonly number[]
if ('push' in x && typeof x.push === 'function'){
x.push(1)
} The lack of those properties does prevent accidentally treating a
The type of
I'm realizing this, and I think it might be a limitation of the TypeScript type system that you can't meaningfully encode a // @target: ES2022
type T = symbol;
function Make<T>(): T{ throw new Error("unimplementable") }
// Array versus readonly Array
Make<ReadonlyArray<T>>() satisfies Array<T>;
Make<Array<T>>() satisfies ReadonlyArray<T>;
// ReadonlyArray < Array
// property versus readonly property
Make<{readonly a: T}>() satisfies {a:T}
Make<{a: T}>() satisfies {readonly a:T}
// property and readonly property are freely interconvertible
// property implementation
type GetX = {
get x(): T
set x(value: never)
}
type SetX = {
set x(value: T)
get x(): unknown
}
type GetSetX = {x: T}
Make<GetSetX>() satisfies GetX;
Make<GetX>() satisfies GetSetX;
// GetX and GetSetX are freely interconvertible,
Make<GetX>() satisfies SetX;
Make<SetX>() satisfies GetX;
// GetX < SetX
Make<GetSetX>() satisfies SetX;
Make<SetX>() satisfies GetSetX;
// GetSetX < SetX |
You can't represent "illegal methods" in TypeScripts type-system. And you can't represent immutability in TypeScripts type-system.
With that argument everything is pointless, because |
Indeed; I was implicitly including |
I would think you could by making the function signature require an argument of type
Yeah. I don’t understand why my above implementation of
Emphasis on “implicitly”. Yes, ———- At any rate, I think this issue is a design limitation (at least unless/until #13347 is resolved) |
It's valid to call functions expecting an argument of
#13347 wouldn't change anything, because, again, your type says it has a |
Yes. Such a function is callable only by constructing a value of type
It wouldn’t fix the issue directly, but it would allow either declaring a function To make a push method safe, you’d do something similar with a constraint on the type of |
|
That’s true. A The I fail to see how an operation which calls the setter could possibly be in semantic agreement with something declared |
This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
🔎 Search Terms
readonly length, array
🕗 Version & Regression Information
⏯ Playground Link
https://www.typescriptlang.org/play?target=99&jsx=0&ts=5.4.0-dev.20231205#code/GYVwdgxgLglg9mABAdxlAFgMQE5wF4CmYAMkQOYYA8AgogQB5REAmAzouANZhzJgDaAXQB8ACgCG2AFzUAlAFgAUAG8liRBASsoibAVYgANjoC8iatmziAngDpguALYTsCxeoDyAIwBWBaLbMBMAwYAQACrgADgTYUNaiegbGADQARIbkGGkpysjYaOJemVLA4oasBAC+bup6UCDYSElGOuLstABkiMq6BOLMCIbWiJlgFOhS5vwA5GMTM4KIVUorikqaYNqIjtYWViNmqBg4+ESk4xii-ACMKYgATPcAzIJuu-s2tlEgrOiiABZZIgAPQgxAAOTgiHiMToljg2FsiAASuBYI4CPDcEigA
💻 Code
🙁 Actual behavior
Typescript accepts the above code. The code crashes at runtime with a runtime
TypeError
like:🙂 Expected behavior
The
push
method should be rejected by the type checker.Additional information about the issue
Partial overlap with a similar issue involving tuple types #40316
The text was updated successfully, but these errors were encountered: