Overload not typing object literals
shouldn’t only “real” show up as a property here? if not, how could I achieve that?

53 Replies
apologies for the shitty screenshot I’m on my mom’s laptop rn lmfao
Based on the documentation, it seems like you're asking about TypeScript's type inference and how it interacts with object literals and function overloads. However, without a specific code example, it's difficult to provide a precise answer.
In general, TypeScript uses static types and type inference to determine the properties and methods available on an object. If you're seeing unexpected properties, it might be due to the way your types or interfaces are defined.
If you're working with function overloads, the order of the overload signatures is important. TypeScript will use the first matching overload definition.
If you could provide a specific code example, I could give a more accurate answer. 🦕
I did provide a code example
???
lines 7 through 18
bro it's AI. AI can't read your screenshot
oh lmao what
I thought someone came in and ran a command or something
here's the code example sir since you cannot read screenshots
I would have expected only the
real property to show up in the object literal, since that's the overload I've chosen from true. If I type fake, it errors out.The behavior you're seeing is due to TypeScript's structural typing system. When you call
A(true, {...}), TypeScript doesn't immediately know which overload to pick. It sees that both Real and Fake are objects and that they could potentially match the object literal you're providing. Therefore, it suggests both real and fake properties.
However, once you start typing the object literal, TypeScript can start narrowing down which overload is correct. If you type { real: ... }, it will match the Real overload, and if you type { fake: ... }, it will match the Fake overload. If you provide a property that doesn't match the overload you're trying to use (like using fake when real is true), TypeScript will give an error.
If you want to avoid this, you could make your types more distinct so TypeScript can tell them apart more easily. For example, you could add a required type field to your Real and Fake types:
Now, TypeScript can tell the difference between Real and Fake as soon as you start typing the object literal, and it will only suggest the correct properties.why can't it tell which object to use from the boolean? it explicitly states which object goes with what
The TypeScript compiler doesn't evaluate the actual values of the arguments when determining which overload to use. Instead, it looks at the types of the arguments. In your case, the
real argument is of type boolean, which could be either true or false. Therefore, TypeScript considers both overloads as potential matches.
When you're calling the function A(true, {...}), TypeScript doesn't immediately know which overload to pick based on the true value. It sees that both Real and Fake are objects and that they could potentially match the object literal you're providing. Therefore, it suggests both real and fake properties.
However, once you start typing the object literal, TypeScript can start narrowing down which overload is correct. If you type { real: ... }, it will match the Real overload, and if you type { fake: ... }, it will match the Fake overload. If you provide a property that doesn't match the overload you're trying to use (like using fake when real is true), TypeScript will give an error.
This behavior is due to TypeScript's structural typing system. It's not about the actual values, but about the types of the values.by this logic, shouldn't this be able to tell which object to use based on whether the type is a boolean or string?
In your code example, TypeScript will indeed be able to determine which overload to use based on whether the
version argument is a string 'V2' or a boolean.
When you call A('V2', {...}), TypeScript knows to use the V2 overload, and it will only suggest the v2 property when you start typing the object literal. If you provide a property that doesn't match the V2 type (like using v3), TypeScript will give an error.
Similarly, if you call A(true, {...}) or A(false, {...}), TypeScript knows to use the V3 overload, and it will only suggest the v3 property when you start typing the object literal. If you provide a property that doesn't match the V3 type (like using v2), TypeScript will give an error.
This is because TypeScript uses the types of the arguments to determine which overload to use. In this case, the types are distinct ('V2' is not a boolean), so TypeScript can tell the overloads apart based on the version argument.except I can see both v2 and v3 as properties in intellisense
The behavior you're seeing is due to TypeScript's structural typing system. When you call
A('V2', {...}), TypeScript doesn't immediately know which overload to pick. It sees that both V2 and V3 are objects and that they could potentially match the object literal you're providing. Therefore, it suggests both v2 and v3 properties.
However, once you start typing the object literal, TypeScript can start narrowing down which overload is correct. If you type { v2: ... }, it will match the V2 overload, and if you type { v3: ... }, it will match the V3 overload. If you provide a property that doesn't match the overload you're trying to use (like using v3 when version is 'V2'), TypeScript will give an error.
This behavior is due to TypeScript's structural typing system. It's not about the actual values, but about the types of the values.but you said
it will only suggest the v2 propertyI apologize for the confusion. The TypeScript compiler uses the types of the arguments to determine which overload to use. However, when it comes to providing suggestions via Intellisense in your code editor, it might still show all possible properties from all overloads until you start typing and it can infer the correct type. This behavior can vary depending on the code editor and its TypeScript support.
In your case, even though you've specified 'V2' or boolean as the argument, the editor's Intellisense might still show both
v2 and v3 properties as it doesn't evaluate the actual values of the arguments. Once you start typing the object literal, TypeScript can start narrowing down which overload is correct.
Please note that this is a limitation of the editor's Intellisense and not TypeScript's type system. The TypeScript compiler itself will correctly match the overloads based on the provided arguments when the code is compiled.I am probably gonna start a robot revolution if I keep bugging this AI
another question: is it possible to remove every
another question: is it possible to remove every readonly component on a type?Yes, it is possible to remove the
readonly modifier from properties of a type in TypeScript. You can do this by using the -readonly modifier in a mapped type. Here's an example:
In this example, MutableType is a mapped type that goes through each property (P) in ReadOnlyType. For each property, it removes the readonly modifier and keeps the original type of the property (ReadOnlyType[P]). The resulting MutableType has the same properties as ReadOnlyType, but none of them are readonly.
Please note that this only removes the readonly modifier from the properties of the type itself. If a property is an object that has its own readonly properties, those will not be made mutable. You would need to apply the mapped type to those properties as well if you want them to be mutable.can this be done recursively?
The documentation does not provide specific information on whether the removal of the
readonly modifier from properties of a type can be done recursively. The provided method only removes the readonly modifier from the properties of the type itself. If a property is an object that has its own readonly properties, those will not be made mutable by this method. You would need to apply the mapped type to those properties as well if you want them to be mutable. However, a recursive solution would require a more complex type manipulation which is not directly covered in the provided documentation.would you be able to make one?
I'm sorry, but I need more context to provide a helpful response. Could you please clarify what you would like me to make?
a type that recursively removes readonly from every property
Sure, here's a TypeScript type that recursively removes
readonly from every property:
This type uses a combination of mapped types and conditional types to recursively walk through every property of T. If a property is an array, it makes the elements of the array mutable. If a property is an object (but not a function), it makes the properties of that object mutable. If a property is a primitive value or a function, it leaves it as is.
Here's how you can use it:
In this example, MutableType has the same structure as ReadOnlyType, but none of the properties are readonly, even in nested objects.DeepMutable produces the following warning:
The warning you're seeing is from Deno's linter, which discourages the use of
Function as a type. When you use Function as a type, you're saying that a value can be any function or class, without specifying what arguments the function should take or what it should return. This can lead to issues with type safety, because TypeScript can't check that you're using the function correctly.
In the DeepMutable type, this line is likely causing the warning:
This line checks if a property is a function. If it is, the property is left as is. The linter warning is saying that this isn't safe, because it doesn't provide any information about what the function's arguments or return type should be.
To fix this warning, you would need to replace Function with a more specific function type. However, in this case, it might not be straightforward to do so. The DeepMutable type is meant to be a general utility type that can be used with any object structure, and the functions within that object could have any number of arguments and any return type.
If you're sure that your usage of Function here is safe and you want to ignore the linter warning, you can do so by adding a // deno-lint-ignore ban-types comment on the line before the warning:
This will tell Deno's linter to ignore the ban-types rule on the next line.could you make the same thing that ADDS readonly to everything?
Sure, here's a TypeScript type that recursively adds
readonly to every property:
This type uses a combination of mapped types and conditional types to recursively walk through every property of T. If a property is an array, it makes the elements of the array readonly. If a property is an object, it makes the properties of that object readonly. If a property is a primitive value, it leaves it as is.
Here's how you can use it:
In this example, ReadonlyType has the same structure as MutableType, but all of the properties are readonly, even in nested objects.this causes functions to have the
DeepReadonly property on them which causes them to not be callableThe
DeepReadonly type provided earlier is designed to make all properties of an object readonly, including functions. However, making a function readonly doesn't prevent it from being callable. It only prevents the function from being reassigned.
Here's an example:
In this example, example.prop2 is a function, and it's still callable even though it's readonly. The readonly modifier only prevents example.prop2 from being reassigned to a different function.
If you're seeing an error that a function is not callable, it might be due to a different issue. If you could provide more details about the error and the code that's causing it, I might be able to help you troubleshoot it.
this produces an error:
The error message is indicating that the
push method does not exist on the type DeepReadonly<typeof rm.geometry>. This is because the DeepReadonly type recursively makes all properties of an object readonly, and in TypeScript, readonly arrays do not have the push method.
In your code, rm.geometry() likely returns an array (since you're able to call push on it), and DeepReadonly<typeof rm.geometry> represents a function that returns a readonly version of that array. Since readonly arrays in TypeScript don't have the push method, you're seeing an error when you try to call push on b.
If you want to make a deep readonly copy of the array returned by rm.geometry(), you should call the function and then apply DeepReadonly to the result, like this:
In this code, b is a deep readonly copy of the array a, and trying to call push on b will result in a TypeScript error.rm.geometry() is not an array, sorry. hopefully this is more clearThe
DeepReadonly type provided earlier is designed to make all properties of an object readonly, including functions. However, making a function readonly doesn't prevent it from being callable. It only prevents the function from being reassigned.
Here's an example:
In this example, example.prop2 is a function, and it's still callable even though it's readonly. The readonly modifier only prevents example.prop2 from being reassigned to a different function.
If you're seeing an error that a function is not callable, it might be due to a different issue. If you could provide more details about the error and the code that's causing it, I might be able to help you troubleshoot it.
this produces the following error:

The error you're seeing is due to how the
DeepReadonly type is defined. It recursively applies readonly to all properties of an object, including functions. In TypeScript, when you apply readonly to a function, it means that the function itself cannot be reassigned, but it doesn't prevent the function from being called.
However, in your DeepReadonly type, when it encounters a function (which is an object in JavaScript), it recursively applies DeepReadonly to the function's properties, not the function itself. This is why you're seeing the error that the function is not callable.
One way to fix this is to modify the DeepReadonly type to handle functions differently. Here's an example:
In this version of DeepReadonly, when it encounters a function (identified by (...args: any[]) => any), it leaves the function as-is instead of trying to apply DeepReadonly to the function's properties. This should allow you to call methods on DeepReadonly objects.I get a warning from
anyThe warning you're seeing is likely due to TypeScript's
noImplicitAny option, which is enabled by default in Deno. This option triggers a warning whenever the any type is used implicitly, such as when a function parameter's type is not specified.
To resolve this warning, you should explicitly specify types wherever possible. If you intentionally want to use the any type, you can do so explicitly to avoid the warning. For example:
In this code, bar is explicitly typed as any, so you won't see a warning.
However, using any is generally discouraged in TypeScript because it bypasses type checking. If you're not sure what type a variable should be, it's often better to use unknown instead. This forces you to perform some kind of type checking before you can use the variable.
If you want to disable the noImplicitAny option, you can do so by creating a tsconfig.json file and setting noImplicitAny to false. However, this is generally not recommended because it makes your code less type-safe.ok more problems, I get a massive error here:
from the expression going into
geometry.push in this function:
getActiveDiff().geometry is Geometry[] and this outer push function is in the Geometry class.
here's what the copy function looks like:
The error message is indicating that the TypeScript compiler is having trouble assigning the result of the
copy(this) function to the push method of the Geometry class. This is because the copy function returns a DeepMutable<T>, but the push method is expecting a Geometry.
The DeepMutable<T> type is a utility type that makes all properties of T mutable (i.e., not readonly). However, it seems like the push method of the Geometry class is not designed to handle this kind of object.
One way to fix this issue is to ensure that the copy function returns a Geometry object when it's called with a Geometry argument. This could be done by adding a type guard to the copy function:
This tells TypeScript that if obj is a Geometry, the function will return a Geometry. Otherwise, it will return a DeepMutable<T>.
However, this might not be the best solution if the copy function is used in many places in your code, as it could potentially break other parts of your code that rely on the copy function returning a DeepMutable<T>.
Another solution could be to modify the push method of the Geometry class to accept a DeepMutable<Geometry>:
This tells TypeScript that the copy(this) expression will always return a DeepMutable<Geometry>, which should be compatible with the push method.
Please note that these solutions might not work perfectly depending on the rest of your code, and you might need to adjust them to fit your specific use case. If you're still having trouble, could you provide more details about theGeometry class and the getActiveDiff function?the problem is that
DeepMutable<Geometry> is not compatible with the Geometry arrayThe issue you're encountering is due to the type incompatibility between
DeepMutable<Geometry> and Geometry. The DeepMutable<T> type is a utility type that makes all properties of T mutable (i.e., not readonly). However, the Geometry array is expecting elements of type Geometry, not DeepMutable<Geometry>.
One way to resolve this issue is to ensure that the copy function returns a Geometry object when it's called with a Geometry argument. This could be done by adding a type guard to the copy function:
This tells TypeScript that if obj is a Geometry, the function will return a Geometry. Otherwise, it will return a DeepMutable<T>.
However, this might not be the best solution if the copy function is used in many places in your code, as it could potentially break other parts of your code that rely on the copy function returning a DeepMutable<T>.
Another solution could be to modify the push method of the Geometry class to accept a DeepMutable<Geometry>:
This tells TypeScript that the copy(this) expression will always return a DeepMutable<Geometry>, which should be compatible with the push method.
Please note that these solutions might not work perfectly depending on the rest of your code, and you might need to adjust them to fit your specific use case. If you're still having trouble, could you provide more details about the Geometry class and the getActiveDiff function?ok so, I want a function that takes in an array of numbers and converts them from degrees to radians. The only thing is that:
- I want the function to prefer a tuple, so if I input
[0,0,0], I should get out [number, number, number]
- I want the function to allow for readonly inputs, since the returned array will be a new array from mapSure, you can create a function in TypeScript that takes in an array of numbers (preferably a tuple) and returns a tuple of the same length. The function can also accept readonly inputs. Here's how you might do it:
In this function, the
readonly keyword is used to indicate that the input array should not be modified. The function returns a new array (also marked as readonly) that contains the radian values.
However, this function does not enforce that the input and output are tuples. In TypeScript, a tuple is a special kind of array with a fixed length and known types. If you want to enforce that the input and output are tuples of the same length, you would need to use a more complex type:
In this function, T is a generic type that extends readonly number[], representing a tuple of numbers. The return type { [K in keyof T]: number } is a mapped type that represents a tuple of the same length as T, where each element is a number.
Please note that the as any cast is necessary because TypeScript cannot guarantee that the map function returns an array of the same length as the input. However, since we know that map does not change the length of the array, this cast is safe.ok how about this, can you make the function also take in a
number and return a converted number?Yes, you can modify the function to accept either a single number or an array of numbers. This can be achieved using function overloads in TypeScript. Here's how you might do it:
In this code, the first two lines are function signatures that tell TypeScript what types of arguments the function can accept and what it should return. The third line is the actual function implementation.
If you call
degreesToRadians with a single number, it will return a single number. If you call it with an array of numbers, it will return an array of numbers. The readonly keyword is used to indicate that the input array should not be modified.this does not prefer a tuple,
degreesToRadians([1]) gives me number[] when I want it to give me [number]In TypeScript, the distinction between
number[] and [number] is subtle. Both represent an array of numbers, but [number] is a tuple type that specifically represents an array with one element, while number[] represents an array with any number of elements.
The function degreesToRadians as currently written will always return number[], because the map function always returns an array, and TypeScript does not have a way to infer that the returned array should have the same length as the input array.
If you want to enforce that the function returns a tuple when given a tuple, you could use a more complex type:
In this function, T is a generic type that extends readonly number[], representing a tuple of numbers. The return type { [K in keyof T]: number } is a mapped type that represents a tuple of the same length as T, where each element is a number.
However, please note that this function will still return an array when called with an array. The tuple type is only enforced at compile time, and at runtime, there is no difference between an array and a tuple in JavaScript.the thing is that I want it to assume a raw input such as
degreesToRadians([0]) is a tuple, instead of assuming it's a number[]In TypeScript, the distinction between
number[] and [number] is subtle. Both represent an array of numbers, but [number] is a tuple type that specifically represents an array with one element, while number[] represents an array with any number of elements.
The function degreesToRadians as currently written will always return number[], because the map function always returns an array, and TypeScript does not have a way to infer that the returned array should have the same length as the input array.
If you want to enforce that the function returns a tuple when given a tuple, you could use a more complex type:
In this function, T is a generic type that extends readonly number[], representing a tuple of numbers. The return type { [K in keyof T]: number } is a mapped type that represents a tuple of the same length as T, where each element is a number.
However, please note that this function will still return an array when called with an array. The tuple type is only enforced at compile time, and at runtime, there is no difference between an array and a tuple in JavaScript.I'll give you an example of what I mean.
the only with this is, as soon as I try to include readonly functionality everything breaks unexpectedly:
The issue you're encountering is due to the way TypeScript handles
Readonly types. When you use Readonly<T>, TypeScript treats the input as an immutable version of T. However, when T is a union type like [] | number[], TypeScript can't guarantee that the input is a tuple, so it defaults to treating it as an array.
In your case, when you call preferTuple([1,2]), TypeScript sees the input as an array of numbers, not a tuple, because it's being passed as a Readonly type. This is why you're seeing (1, 2)[] as the output instead of [number, number].
When you call preferTuple([1,2] as [number, number]), TypeScript knows that the input is a tuple because you've explicitly cast it as such. This is why you're seeing [number, number] as the output.
Finally, when you call preferTuple([1,2] as Readonly<[number, number]>), TypeScript treats the input as a readonly array, not a tuple, because of the Readonly type. This is why you're seeing number | [] as the output.
If you want TypeScript to treat the input as a tuple, you'll need to explicitly cast it as such. Unfortunately, TypeScript doesn't currently have a way to infer that a readonly array should be treated as a tuple.would there be any way to detect if the input is
Readonly and make a mutable type out of it to infer it that way?The documentation does not provide a direct way to detect if a type is
Readonly and then make a mutable type out of it. TypeScript's type system does not provide a built-in mechanism for this.
However, you can create a type that removes the readonly modifier from all properties of a type using mapped types. Here's an example:
This Mutable type takes a type T and produces a new type where all properties are mutable. The -readonly syntax in the mapped type removes the readonly modifier from each property.
You can use this Mutable type to create a mutable version of a Readonly type. For example:
In this example, ReadonlyPoint is a Readonly version of { x: number; y: number }, and MutablePoint is a mutable version of ReadonlyPoint.
However, this does not infer whether the input type was Readonly or not. It simply ensures that the resulting type is mutable. If the input type was not Readonly, Mutable<T> will be identical to T.