I am writing 2 classes, Project
and User
, each of which has a find
method that needs to call an api rest call
attempt #1
class Project {
find(params) {
return request({url: "/api/Project", qs: params});
}
}
class User {
find(params) {
return request({url: "/api/User", qs: params});
}
}
now, this is obviously not very good ;) There are no checks on the parameters, no types defined, duplicate code etc etc
attempt #2
class Base {
constructor(private name:string) {
}
find(options) {
return request({url: `/api/${this.name}`, qs: params});
}
}
class Project extends Base{
constructor() { super("Project"); }
}
class User {
constructor() { super("User"); }
}
so, slightly better. less code duplication. Still no type checking. Interfaces to the rescue ;)
attempt#3
interface IParams { token: string }
class Base {
constructor(private name:string) {
}
find(params:IParams) {
return request({url: `/api/${this.name}`, qs: params});
}
}
class Project extends Base{
constructor() { super("Project"); }
}
class User extends Base {
constructor() { super("User"); }
}
this is where I started to hit some problems. The Project and User api params object both require the token
property. However, they also require userDd
and projectId
to be set
At the moment, I need to add both of those to the IParams interface, which seems wrong.
attempt#4
interface IUserParams { userid:number, token: string }
interface IProjectParams { projectid:number, token: string }
interface IProject {
find(params:IProjectParams)
}
interface IUser {
find(params:IUserParams)
}
class Base {
constructor(private name:string) {
}
find(params) { // I have no idea on how to "type" params
return request({url: `/api/${this.name}`, qs: params}); // likewise no idea on how to type the return value
}
}
class Project extends Base implements IProject {
constructor() { super("Project"); }
}
class User extends Base implements IUser {
constructor() { super("User"); }
}
However, this does not help : as the Base class defines the find
method, how can the compiler verify that for user, userid
and token
are passed - also, that no other parameter is passed, and likewise for project
This also led me onto thinking about the return value of the find
method : for projects I want an array of IPromiseModel
, and for user, IUserModel
I have tried chaning the IProject
interface to read
interface IProject {
find(params:IProjectParams):Promise<IProjectModel[]>
}
but I still can pass any property into the params
- ie I can do
Project.find({token: "1234",foobar:true})
I suspect this is because I haven't defined a type for the parameter in the Base find
I know that generics must play a part in this, but for the life of me I cannot get a definition working that matches these requirements
I am using typescript 2.2.2
With generics you can do this:
interface IParams { token: string }
interface IUserParams { userid:number, token: string }
interface IProjectParams { projectid:number, token: string }
class Base<TEntity, TParams extends IParams> {
constructor(private name:string) {
}
find(params: TParams): Promise<TEntity[]> {
return request({url: `/api/${this.name}`, qs: params});
}
}
class Project extends Base<Project, IProjectParams> {
constructor() { super("Project"); }
}
class User extends Base<User, IUserParams> {
constructor() { super("User"); }
}
new User().find({
userid: 123,
token: 'test'
});
The constraint in the Base class TParams extends IParams
here is optional, since you are not explicitly accessing the token property.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.