-
Notifications
You must be signed in to change notification settings - Fork 12.8k
(suggestion) Overrides in extending class and interface definitions. #3402
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
Comments
But then |
Very true, and that's usually the first route I would take. I've been hoping to avoid that though. Lately, my free time has been spent writing type definitions for DefinitelyTyped. Since the projects I'm defining interfaces for aren't my own, I was hoping to keep the types as strict to the project as possible. That aside, the reason I wanted to suggest this was to point out an example where a more JS approach to objects and inheritance had value. Having types and laying strict constraints on inheritance is really nice, especially for someone who grew up in Java. However, the design philosophy for JS is more free form and there are a few liberties that it provides that become missed when I more strict type design is taken. On that note though, I do want to say that I'm mostly anxious to suggest ideas because I think TypeScript is awesome and I really appreciate the time that all of you take to post back to suggestions like these, even when it's just an anxious young programmer who often times comes off like he can't be wrong. |
However, if I am holding an object of type B and I call build() on that object, I know that I will receive a value of type SomeOtherType. But when you are holding an object of type B through a value of type A then what? interface A {
build(): number;
}
interface B extends A{
build(): string;
}
var a: A;
var b: B;
a = b;
var result = a.build();
var aNumberOrACrash = result.toFixed() The point of interfaces is really to verify contracts and prevent situations like this. It sounds like you're more interested in using interfaces to mix in existing functionality for code re-use (although ideally you'd also be able to mix in an actual implementation). We've previously held off on this kind of feature because it has been proposed for ES7 (or later) and we're hesitant to implement things which may later conflict with the ES standard. There isn't really a canonical thread for discussion on there but if you search the issue tracker for 'mixin' you'll find a few different threads where we've talked about options: https://github.com/Microsoft/TypeScript/search?q=mixin&type=Issues&utf8=%E2%9C%93 Thanks for the feedback though, keep it coming :) |
Thank you for the info. |
Wrapper module usually just override one (or some) method of the original module. How should I write .d.ts for it if not to modify the .d.ts file of the original module? |
We would find it really useful to be able to do this also. In a number of places we are using a third party typing for some interface that declares one of it's sub properties or methods as as type any and we would like to create more strongly typed interfaces based on these. For example the angular.ui.IStateService interface has a property called current which in turn has a property called data for storing arbitrary ....wait for it ... data (shocking I know). It would be great if we could create typings that more strongly type the data property so that we have typing in the state controller. We could get the same effect by declaring an object of a custom type and setting it to the value of $state.current.data but this is more code. EDIT |
@ttowncompiled why not throw a compiler error if an overload has the same parameters with different return type? I think this is what C++/Java compilers do, because overload is only possible for different types/number of parameters(otherwise it would be impossible for the compiler to determine which method to call). To argument in favor of implementing this feature, I will describe a use case of some real world libraries that would benefit from overloading in subinterface: levelup and its extension sublevel. Levelup interface Batch {
type: string;
key: any;
value?: any;
keyEncoding?: string;
valueEncoding?: string;
} The sublevel library usage is something like this: import levelup = require('levelup');
import sublevel = require('level-sublevel');
var db = sublevel(levelup('/path/to/db')); The /// <reference types="levelup" />
interface Hook {
(ch: any, add: (op: Batch|boolean) => void): void;
}
interface Batch {
prefix?: Sublevel;
}
interface Sublevel extends LevelUp {
sublevel(key: string): Sublevel;
pre(hook: Hook): Function;
}
declare module "level-sublevel" {
function sublevel(levelup: LevelUp): Sublevel;
export = sublevel;
} The interesting part is that the interface SubBatch extends Batch {
prefix?: Sublevel;
} But since it is not possible for The problem with this approach is that the |
@danquirk I think this was prematurely declined. Here's an example of where this might be extremely useful: import { SomeComponent, SomeComponentProps } from "./SomeComponent";
interface BlahProps {
// SomeComponentProps has an onChange method with a different signature.
onChange: (someTest: string) => void,
}
class Blah extends React.Component<BlahProps & SomeComponentProps, any> {
handleChildChange = (e: any) => {
// do something with the event child event
}
render() {
let { onChange, ...other } = this.props;
return <SomeComponent onChange={this.handleChildChange} {...other} />;
}
} Whether you use a union type or extend the type, the There will never be anything accessing through the base type Perhaps the best solution could be a way to create a new type that omits some properties from an existing interface? interface A {
t1: string;
t2: number;
other: object;
}
type B = A without t1, other;
interface C extends B {
t3: object;
}
// result: C has only t2, t3. |
If you really want to modify a property on some interface you can workaround by producing intermediate type that will weaken desired property to be modified: export interface A {
prop1: string;
prop2: number;
}
// This is intermediate type and can be kept private
interface AWeak extends A {
prop1: any
}
export interface ANew extends AWeak {
prop1: boolean; // No errors here as `prop1` is already of type `any`
} EDIT: I just played a little bit with this and created a mapped type that will allow you to skip extra type creation in order to override desired prop, I called it type Weaken<T, K extends keyof T> = {
[P in keyof T]: P extends K ? any : T[P];
}; And then you can simply: export interface A {
prop1: string;
prop2: number;
}
export interface ANew extends Weaken<A, 'prop1'> {
prop1: boolean; // No errors here as `prop1` is weakened to type `any`
} What do you think should this helper type be added to Typescript's default definitions library? |
Using this example:
The compiler will thrown an error that SomeOtherType is not assignable to SomeType. However, if I am holding an object of type B and I call build() on that object, I know that I will receive a value of type SomeOtherType.
I've currently used any as an override, but it would nice to be able to override the return type of functions on a parent class or interface.
The text was updated successfully, but these errors were encountered: