-
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
Better support for type bounds in generics #13337
Comments
const xs = [{ a: 'A' }];
const ys = [{ a: 'A', b: 'B' }];
const zs = ys.concat(xs);
declare global {
interface Array<T> {
concat<A extends B, B>(this: A[], ...items: B[][]): B[];
concat<A extends B, B>(this: A[], ...items: (B | B[])[]): B[];
}
} no new features required. The problem with removing the current error is that it drastically changes the meaning of existing code where a type parameter is being shadowed class Container<A> {
constructor(value: A) { }
act<A extends B, B>(b: B) { /*...*/ }
} I'm not sure what the right notation is but See also #1394. |
@jiaweihli can you please share the real code behind this need ? @aluanhaddad |
@akarzazi correct, but they do not mean the same thing. |
I just realized that I can already accomplish what I want, trivially, with the following declare global {
interface Array<T> {
concat<A extends B, B>(this: A[], ...items: B[][]): B[];
concat<A extends B, B>(this: A[], ...items: (B | B[])[]): B[];
}
} @jiaweihli I believe you can do the same: class Container<A> {
constructor(private value: A) { }
act<A extends B, B>(this: Container<A>, b: B) { /*...*/ }
} |
@aluanhaddad you mean: interface Array<T> {
concat<T extends B, B>(this: T[], ...items: B[][]): B[];
concat<T extends B, B>(this: T[], ...items: (B | B[])[]): B[];
} Edit: interface Array<T> {
concat<T extends B, B>(...items: B[]): B[];
concat<T extends B, B>(...items: (B | B[])[]): B[];
} |
@akarzazi it doesn't actually matter if the type parameter name is |
@aluanhaddad see edit |
I'm not sure I follow you. The definitions without a this const zs = ys.concat(xs); that gives interface Array<T> {
concat<T extends U, U>(this: T[], ...items: U[][]): U[];
concat<T extends U, U>(this: T[], ...items: (U | U[])[]): U[];
} infers the lower bound. Note that the method level |
@aluanhaddad Sorry I didn't open VS to check. interface Array<T> {
add2<T extends B, B, C>(...items: B[]): B[];
add3<A extends B, B>(this: A[],...items: B[]): B[];
}
interface Type {
a: string;
}
interface SubType extends Type {
b: string;
}
var a: SubType[] = [];
let baseTypeInst: Type = { a: "a" };
let notBaseTypeInst: Event;
a.add2(baseTypeInst); // ok
a.add2(notBaseTypeInst); // No error!
a.add3(notBaseTypeInst); // error: subtype is not assignable to the type Event It seems that It's worth mentioning that in C# behaves similarly public class MyClass<T> where T : ICloneable
{
public void Do<T>(T param) //Warning CS0693
{
param.Clone(); // Clone is not defined on param
}
}
public interface IMyClass<T> where T : ICloneable
{
void Do<T>(T param); //Warning CS0693
} but there is a warning :
|
@aluanhaddad Yup, the code you posted sets lower bounds correctly. |
@aluanhaddad I have a follow up question. Consider the following function in some generic class, foo<A extends B, B>(b: B) { /* ... */ } As your code above suggested, this ensures that B is a superclass of A. But what if class Animal {}
class Cat extends Animal {}
class Kitten extends Cat {} What should I do if I want to enforce that foo<Kitten extends B, B>(b: B) { /* ... */ } won't work because this is trying to declare a new type parameter named |
`getOrElse` and `orElse` use self-types in order to support typed upper bounds.[0] In TypeScript 2.4, generic functions were checked more strictly[1]. This causes the implicit downward type cast to fail, so we explicitly invoke the cast in the method body. This workaround is backwards-compatible with TypeScript 2.3. Bounded polymorphism has been implemented[2], but true F-bounded polymorphism hasn't been. This means a type like `interface Option<A, B = Option<A, B>>` is invalid. Alternatively, we can solve this with a lower type bound, but these don't work against concrete classes[3]. --- We should also upgrade monapt's TypeScript dependency to 2.4, but there are unrelated errors compiling the tests. [0] microsoft/TypeScript#13337 [1] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#stricter-checking-for-generic-functions [2] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#type-parameters-as-constraints [3] microsoft/TypeScript#14520
getOrElse and orElse use self-types in order to support typed upper bounds.[0] In TypeScript 2.4, generic functions were checked more strictly[1]. This causes the implicit downward type cast to fail, so we explicitly invoke the cast in the method body. This workaround is backwards-compatible with TypeScript 2.3. Bounded polymorphism has been implemented[2], but true F-bounded polymorphism hasn't been. This means a type like `interface Option<A, B = Option<A, B>>` is invalid. Alternatively, we can solve this with a lower type bound, but these don't work against concrete classes[3]. --- We should also upgrade monapt's TypeScript dependency to 2.4, but there are unrelated errors compiling the tests. [0] microsoft/TypeScript#13337 [1] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#stricter-checking-for-generic-functions [2] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#type-parameters-as-constraints [3] microsoft/TypeScript#14520
getOrElse and orElse use self-types in order to support typed upper bounds.[0] In TypeScript 2.4, generic functions were checked more strictly[1]. This causes the implicit downward type cast to fail, so we explicitly invoke the cast in the method body. This workaround is backwards-compatible with TypeScript 2.3. Bounded polymorphism has been implemented[2], but true F-bounded polymorphism hasn't been. This means a type like interface Option<A, B = Option<A, B>> is invalid. Alternatively, we can solve this with a lower type bound, but these don't work against concrete classes[3]. --- We should also upgrade monapt's TypeScript dependency to 2.4, but there are unrelated errors compiling the tests. [0] microsoft/TypeScript#13337 [1] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#stricter-checking-for-generic-functions [2] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#type-parameters-as-constraints [3] microsoft/TypeScript#14520
getOrElse and orElse use self-types in order to support typed upper bounds.[0] In TypeScript 2.4, generic functions were checked more strictly[1]. This causes the implicit downward type cast to fail, so we explicitly invoke the cast in the method body. This workaround is backwards-compatible with TypeScript 2.3. Bounded polymorphism has been implemented[2], but true F-bounded polymorphism hasn't been. This means a type like interface Option<A, B = Option<A, B>> is invalid. Alternatively, we can solve this with a lower type bound, but these don't work against concrete classes[3]. --- We should also upgrade monapt's TypeScript dependency to 2.4, but there are unrelated errors compiling the tests. [0] microsoft/TypeScript#13337 [1] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#stricter-checking-for-generic-functions [2] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#type-parameters-as-constraints [3] microsoft/TypeScript#14520
getOrElse and orElse use self-types in order to support typed upper bounds.[0] In TypeScript 2.4, generic functions were checked more strictly[1]. This causes the implicit downward type cast to fail, so we explicitly invoke the cast in the method body. This workaround is backwards-compatible with TypeScript 2.3. Bounded polymorphism has been implemented[2], but true F-bounded polymorphism hasn't been. This means a type like interface Option<A, B = Option<A, B>> is invalid. Alternatively, we can solve this with a lower type bound, but these don't work against concrete classes[3]. --- We should also upgrade monapt's TypeScript dependency to 2.4, but there are unrelated errors compiling the tests. [0] microsoft/TypeScript#13337 [1] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#stricter-checking-for-generic-functions [2] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#type-parameters-as-constraints [3] microsoft/TypeScript#14520
getOrElse and orElse use self-types in order to support typed upper bounds.[0] In TypeScript 2.4, generic functions were checked more strictly[1]. This causes the implicit downward type cast to fail, so we explicitly invoke the cast in the method body. This workaround is backwards-compatible with TypeScript 2.3. Bounded polymorphism has been implemented[2], but true F-bounded polymorphism hasn't been. This means a type like interface Option<A, B = Option<A, B>> is invalid. Alternatively, we can solve this with a lower type bound, but these don't work against concrete classes[3]. --- We should also upgrade monapt's TypeScript dependency to 2.4, but there are unrelated errors compiling the tests. [0] microsoft/TypeScript#13337 [1] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#stricter-checking-for-generic-functions [2] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#type-parameters-as-constraints [3] microsoft/TypeScript#14520
`getOrElse` and `orElse` use self-types in order to support typed upper bounds.[0] In TypeScript 2.4, generic functions were checked more strictly[1]. This causes the implicit downward type cast to fail, so we explicitly invoke the cast in the method body. This workaround is backwards-compatible with TypeScript 2.3. Bounded polymorphism has been implemented[1], but true F-bounded polymorphism hasn't been. This means a type like `interface` Option<A, B = Option<A, B>> is invalid. Alternatively, we can solve this with a lower type bound, but these don't work against concrete classes[2]. --- We should also upgrade monapt's TypeScript dependency to 2.4, but there are unrelated errors compiling the tests. [0] microsoft/TypeScript#13337 [1] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript [2] microsoft/TypeScript#14520
`getOrElse` and `orElse` use self-types in order to support typed upper bounds.[0] In TypeScript 2.4, generic functions were checked more strictly[1]. This causes the implicit downward type cast to fail, so we explicitly invoke the cast in the method body. This workaround is backwards-compatible with TypeScript 2.3. Bounded polymorphism has been implemented[1], but true F-bounded polymorphism hasn't been. This means a type like `interface` Option<A, B = Option<A, B>> is invalid. Alternatively, we can solve this with a lower type bound, but these don't work against concrete classes[2]. --- We should also upgrade monapt's TypeScript dependency to 2.4, but there are unrelated errors compiling the tests. [0] microsoft/TypeScript#13337 [1] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript [2] microsoft/TypeScript#14520
This is currently valid, legal TypeScript:
But reversing the type bound in
act
doesn't work, i.e.is not valid.
Ideally, the class's generic parameter can be used in any position.
Alternatively, we could support lower type bounds through a new keyword, narrows:
(meaning, B is a supertype of A).
Another possible alternative syntax:
Examples of implementations in other languages:
http://rustbyexample.com/generics/where.html
http://docs.scala-lang.org/tutorials/tour/lower-type-bounds.html
The text was updated successfully, but these errors were encountered: