You can achieve what you want without the instanceof keyword as you can write custom type guards now:
interface A {
member: string;
}
function instanceOfA(object: any): object is A {
return 'member' in object;
}
var a: any = {member: "foobar"};
if (instanceOfA(a)) {
alert(a.member);
}
Lots of Members
If you need to check a lot of members to determine whether an object matches your type, you could instead add a discriminator. The below is the most basic example, and requires you to manage your own discriminators... you'd need to get deeper into the patterns to ensure you avoid duplicate discriminators.
interface A {
discriminator: 'I-AM-A';
member: string;
}
function instanceOfA(object: any): object is A {
return object.discriminator === 'I-AM-A';
}
var a: any = {discriminator: 'I-AM-A', member: "foobar"};
if (instanceOfA(a)) {
alert(a.member);
}
Answer from Fenton on Stack OverflowYou can achieve what you want without the instanceof keyword as you can write custom type guards now:
interface A {
member: string;
}
function instanceOfA(object: any): object is A {
return 'member' in object;
}
var a: any = {member: "foobar"};
if (instanceOfA(a)) {
alert(a.member);
}
Lots of Members
If you need to check a lot of members to determine whether an object matches your type, you could instead add a discriminator. The below is the most basic example, and requires you to manage your own discriminators... you'd need to get deeper into the patterns to ensure you avoid duplicate discriminators.
interface A {
discriminator: 'I-AM-A';
member: string;
}
function instanceOfA(object: any): object is A {
return object.discriminator === 'I-AM-A';
}
var a: any = {discriminator: 'I-AM-A', member: "foobar"};
if (instanceOfA(a)) {
alert(a.member);
}
In TypeScript 1.6, user-defined type guard will do the job.
interface Foo {
fooProperty: string;
}
interface Bar {
barProperty: string;
}
function isFoo(object: any): object is Foo {
return 'fooProperty' in object;
}
let object: Foo | Bar;
if (isFoo(object)) {
// `object` has type `Foo`.
object.fooProperty;
} else {
// `object` has type `Bar`.
object.barProperty;
}
And just as Joe Yang mentioned: since TypeScript 2.0, you can even take the advantage of tagged union type.
interface Foo {
type: 'foo';
fooProperty: string;
}
interface Bar {
type: 'bar';
barProperty: number;
}
let object: Foo | Bar;
// You will see errors if `strictNullChecks` is enabled.
if (object.type === 'foo') {
// object has type `Foo`.
object.fooProperty;
} else {
// object has type `Bar`.
object.barProperty;
}
And it works with switch too.
Can a TypeScript type implement an interface? - Stack Overflow
How can I create an object based on an interface file definition in TypeScript? - Stack Overflow
Casting an object to an interface it "doesn't" implement?
Can instanceOf operator be used to check if an object is an instance of a n interface, or type?
What is a TypeScript interface?
What are the types of TypeScript interfaces?
When should I use interfaces in TypeScript?
The answer to the question as asked is no, you cannot do this directly with a type alias. An implements clause only applies to class declarations, and an extends clause only applies to interface or class declarations.
Of course it is easy enough to get analogous functionality:
An implements clause on a class just checks to see if the class instance is assignable to the declared type, and produces a compiler warning if it's not; it has no effect on the type of
the instance. You can do the same thing with a utility type like
type Implements<T, U extends T> = U
So Implements<T, U> doesn't have an effect on the resulting type, U, but since U is constrained to T, you will get a warning if it is not assignable.
Let's test it:
type Cat = Implements<IPet, {
needsFood: boolean,
color: string,
}> // okay
type Dog = Implements<IPet, {
bark(): void
}>; // error! Property 'needsFood' is missing in type '{ bark(): void; }'
Looks good.
Meanwhile an extends clause can be used to add members to or narrow members of a parent type. This is essentially the same as an intersection type, and so we can make a utility type to capture this:
type Extends<T, U extends Pick<T, keyof T & keyof U>> =
T & U;
Here we combine both the parent type T and the new members U. I've constrained U to make sure that you can't add conflicting properties, which is similar to what happens if you try to extend an interface with conflicting properties:
type Cat2 = Extends<IPet, {
color: string
}>
type Dog2 = Extends<IPet, {
needsFood: number // error!
}>; // error!
// Type '{ needsFood: number; }' does not satisfy the constraint Pick<IPet, "needsFood">.
Also looks good.
Those approaches aren't completely identical to implements/extends clauses, but they should be close enough for a lot of use cases. There are almost surely edge cases where they differ and it's possible these could be repaired or worked around. But the basic takeaway here is that you can use generic constraints and intersection types to build a solution.
Playground link to code
In TypeScript, you can indeed extend a type with an interface. The syntax for extending a type with an interface is using the extends keyword. Here's an example:
interface Shape {
color: string;
}
type Square = Shape & {
sideLength: number;
}
let square: Square = {
color: "blue",
sideLength: 10
};
This creates a new type Square that extends the Shape interface with an additional property sideLength. You can also use interfaces with classes for defining the shape of the instances of the class. Classes in TypeScript can implement interfaces to enforce that the class meets the structure defined by the interface.
So, you can use both types and classes to work with interfaces in TypeScript.
If you are creating the "modal" variable elsewhere, and want to tell TypeScript it will all be done, you would use:
declare const modal: IModal;
If you want to create a variable that will actually be an instance of IModal in TypeScript you will need to define it fully.
const modal: IModal = {
content: '',
form: '',
href: '',
$form: null,
$message: null,
$modal: null,
$submits: null
};
Or lie, with a type assertion, but you'll lost type safety as you will now get undefined in unexpected places, and possibly runtime errors, when accessing modal.content and so on (properties that the contract says will be there).
const modal = {} as IModal;
Example Class
class Modal implements IModal {
content: string;
form: string;
href: string;
$form: JQuery;
$message: JQuery;
$modal: JQuery;
$submits: JQuery;
}
const modal = new Modal();
You may think "hey that's really a duplication of the interface" - and you are correct. If the Modal class is the only implementation of the IModal interface you may want to delete the interface altogether and use...
const modal: Modal = new Modal();
Rather than
const modal: IModal = new Modal();
If you want an empty object of an interface, you can do just:
var modal = <IModal>{};
The advantage of using interfaces in lieu of classes for structuring data is that if you don't have any methods on the class, it will show in compiled JS as an empty method. Example:
class TestClass {
a: number;
b: string;
c: boolean;
}
compiles into
var TestClass = (function () {
function TestClass() {
}
return TestClass;
})();
which carries no value. Interfaces, on the other hand, don't show up in JS at all while still providing the benefits of data structuring and type checking.