I have an abstract super class that defines a property "proposal".
export abstract class myBaseClass {
public proposal: Proposal;
}
and a class that extends it
export class mySubClassComponent Component extends myBaseClass{
constructor() {
super();
}
}
I try to access the property "proposal" of myBaseClass in the template of mySubClassComponent like this:
*ngIf="proposal.position"
but I'm getting the following error
TypeError: Cannot read property 'position' of undefined
how can I have access to this property inside the mySubClassComponent tempalte?
You are accessing it correctly. However, you have defined the type but, in fact, the class property is actually undefined.
Just add a null check in your ngIf and you will be done:
*ngIf="proposal?.position"
This will avoid undesired errors if proposal is declared but its value is undefined.
Basically, to make it clearer, this:
export abstract class myBaseClass {
public proposal: Proposal;
}
is the same as this:
export abstract class myBaseClass {
public proposal: Proposal = undefined;
}
Keep in mind that, in typescript, declaring a variable type have no effects after the code is compiled. If a variable is undefined, it will be undefined at runtime, regardless the type you have declared in your typescript code.
Related
I'm simulating a multiple inheritance in typescript by this way:
export const FileManager = superClass => class extends superClass {
//...
}
export declare abstract class Model<T extends Model<T>>{
//...
}
I tried the following and then it says that FileManager was expecting 1 parameter instead of 2.
export class Order extends FileManager(Model<Order>)){
//...
}
So I changed the FileManager definition to:
export const FileManager = (superClass,t) => class extends superClass<t> {
//...
}
But then I get this error:
[ts] Value of type 'typeof Model' is not callable. Did you mean to
include 'new'?
It was working well before I needed to declare the Type Assertion to model class (its neccesary, I cant remove it).
I think the problem is the way I receive the 'typeof' as parameter and how to instantiate dynamically.
Im really stuck, I will be very grateful to any help
I try to use a decorator to add some method or property to an annotated class.
This is my decorator :
export default function Component(params) {
return function decorator(target) {
target.template = params.template;
console.log(target, params.template);
}
}
I used it this way :
#Component({
template: template
})
export default class App {}
But when I use this class :
app.template // undefined;
Any idea?
You are modifying class object itself, i.e.
App.template // your template is here
and you just defined a static property for App class in this case.
In order to set template for class instances you should use:
target.prototype.template = params.template;
(Good example that classes are actually just syntactical sugar over constructor functions and prototype-based inheritance).
Also, I think this article about combining mixins and decorators might be helpful.
I'm looking through the React documentation and I've come across this code.
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
Is there a specific name for what they are doing here, where they are creating an object of propTypes on the class?
Is this just a React thing or can this be done in any ES6 code?
Why can't we just set a variable of propTypes within the class itself, why does it have to come outside the class?
That's because propTypes is a static1 property of the class, not associated with a certain instance of the class but the class itself. React's prop type-checking looks for propTypes of a certain component as a static property of the component's class. It's not on the class's prototype, but on the class itself.
If you were to declare it inside the class, it would be an instance property:
class Greeting extends React.Component {
get propTypes() { //Not static!
...
}
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Every Greeting component would then have the property propTypes and React won't properly type-check the props. You could use a static getter and declare it as a static property of the class though:
static get propTypes() {
...
}
The reason it's outside the class is based on preference. Static properties and getters can be used anywhere in ES2015 (or ES6) code.
In future versions of ECMAScript you can declare class properties. You can use class properties now with Babel and the transform-class-properties plugin (also in the stage-2 preset):
class Greeting extends React.Component {
static propTypes = {
...
}
}
This is syntactic sugar and works exactly the same as the static getter acting as a static property of the class.
1 Static meaning "unchanging" because the property doesn't change based on instance, it's the same across all instances because it's not associated with just one instnace.
PropTypes is a React specific API. It's a way that o tell React to perform basic runtime type-checking of the properties you pass to a component. In your example, you are saying that Greeting components can take a name property of type string, but it's not required.
The way that this special propTypes property is defined is not specific to React, though, it's just an ES6 static class property. It's a property associated with the class declaration itself (Greeting.propTypes), not instances of the class (new Greeting().propTypes is undefined). There's actually a newer ES7+ syntax you can use which is equivalent:
class Greeting extends React.Component {
static propTypes = {
name: PropTypes.string
};
render() { }
}
console.log(Greeting.propTypes) // { name: ... }
You declare / define a class and you instantiate objects of a certain class.
For example, in vanilla JS I could easily do something like this:
class BaseClass extends React.Component { ... }
class Foo extends BaseClass { ... }
ReactDOM.render(<Foo />, someEl)
and it just works, no problem.
However, I can't seem to do such a simple thing in TypeScript. I tried to do
class BaseClass<P,S> extends React.Component<P,S> { ... }
interface IFooProps {...}
interface IFooState {...}
class Foo extends BaseClass<IFooProps, IFooState> { ... }
ReactDOM.render(<Foo />, someEl)
but that fails with errors like
ERROR in ./src/app.tsx
(44,17): error TS2605: JSX element type 'Foo' is not a constructor function for JSX elements.
Property 'setState' is missing in type 'Foo'.
ERROR in ./src/app.tsx
(44,17): error TS2607: JSX element class does not support attributes because it does not have a 'props' property
ERROR in ./src/Foo.tsx
(30,49): error TS2339: Property 'props' does not exist on type 'Foo'.
My question is, how do we extend React.Component in order to make a base class where child classes of the base class can still specify the types of their props and state, so that I can do
class Foo extends BaseClass<IFooProps, IFooState> { ... }
where BaseClass extends from React.Component?
The following code is perfectly fine:
class BaseClass<P,S> extends React.Component<P,S> { ... }
and works fine e.g. I use it to add custom behavior to my React components in alm : https://github.com/alm-tools/alm/blob/5ff516f0212f75c7365a56104413d34dddcbf429/src/app/ui.tsx#L11
I'm encapsulating a Menu called JellMenu, and I want to expose CustomMenuItem like JellMenu.Item instead of import CustomMenuItem. I have no idea how to do.
I took look at react-native-viewpager source code, and I think this maybe helpful:
var ViewPager = React.createClass({
statics: {
DataSource: ViewPagerDataSource,
},
It will expose ViewPagerDataSource as ViewPager.DataSource, right? I don't know exactly. what's the meaning of the keyword statics in Es5, and what's the alternative in Es6? Thank you in advance.
It isn't a keyword, it's just a property name in an object initializer being passed to React.createClass. From the documentation, it's used to specify static (non instance-specific) parts of a React class:
The statics object allows you to define static methods that can be called on the component class.
Although statics only works for React.createClass, you can still write static methods in ES6 notation. If you are using ES7, then you can also write static properties.The statics object allows you to define static methods that can be called on the component class. For example:
var MyComponent = React.createClass({
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
},
render: function() {
}
});
MyComponent.customMethod('bar'); // true
Methods defined within this block are static, meaning that you can run them before any component instances are created, and the methods do not have access to the props or state of your components. If you want to check the value of props in a static method, have the caller pass in the props as an argument to the static method.
Also, You can write statics inside ES6+ classes this way:
class Component extends React.Component {
static propTypes = {
...
}
static someMethod(){
}
}
Or outside the class like this:
class Component extends React.Component {
....
}
Component.propTypes = {...}
Component.someMethod = function(){....}