-
-
Notifications
You must be signed in to change notification settings - Fork 548
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
Add JustProps
and JustMethods
types
#4
Conversation
Would maybe |
Can you share some real-life situations where these have been useful? The included examples are good for showing what they do, but not when you would need them. |
JustProps
and JustMethods
types
Co-Authored-By: xxxtonixxx <tonivj5@Gmail.com>
Co-Authored-By: xxxtonixxx <tonivj5@Gmail.com>
I use class User {
name: string;
age: number;
doSomething() { ... }
}
function getUser(id: number): Observable<User> {
return this.http.get<JustProps<User>>(...uri...).pipe(map(user => new User(user));
} Or when I manage only object properties (for example in a form or updating the properties of a database model) function fillForm(user: JustProps<User>): void {
...
}
function insert(user: JustProps<User>): Promise<User> {
return this.userRepository.insert(user);
} In these examples I don't want the user's methods, only need its properties. I think these real-life examples are clear enough, should I include it as examples in the code? I haven't used JustMethods yet, I did it because once Regarding how to call it, I still think JustProps is better, it's more readable from my point of view |
I don't think this is a good idea. I don't see any opportunity to use this in a way that doesn't violate some key tenets of good type modeling, particularly the single responsibility principle. What you've done (with your example), is take a single type (User) and give it two responsibilities: representing user data and representing actions on that data. In a context where you would never have data decoupled from its mutators, that's obviously fine, but that's not the case in your example. You should be using The only thing this type does is allow developers to misuse too-large types rather than refine them into a more granular type hierarchy. I remain completely unconvinced that it's possible to use this in a way that doesn't violate SRP. This is a classic footgun. |
@xxxTonixxx I just added some contribution guidelines. Would you be able to review them? I'm also interested in feedback if anything there is unclear or could be improved. https://github.com/sindresorhus/type-fest/blob/master/.github/contributing.md |
@EdwardDrapkin I agree with your principle, but it is a common pattern in many frameworks: |
@xxxTonixxx Do you have any other use-cases for these types other than the ones mentioned already? |
@CvX @BendingBender Thoughts? |
Not sure whether it's actually useful, I've never needed types like this. |
They have LiveRecords, which is fine. The issue is that he's trying to use the same type to represent just a serialization of data (e.g. from an API) and the LiveRecord itself. |
I use it to avoid creating redundant types, why defining an interface whose purpose to maintein only properties? If my model only changes beetwen my ' If my model and its interface would have different properties or use-cases, I understand to have both. I honestly see this redundant... interface User {
name: string;
age: number;
address: string;
a1: string;
a2: string;
a3: string;
a4: string;
a5: string;
a6: string;
....
}
class UserDAO implements User {
name: string;
age: number;
address: string;
a1: string;
a2: string;
a3: string;
a4: string;
a5: string;
a6: string;
...
doSomething() { ... }
doSomething2() { ... }
doSomething3() { ... }
} When I can just use Another use-case example where I use it's to type constructor class User {
name: string;
age: number;
address: string;
a1: string;
a2: string;
a3: string;
a4: string;
a5: string;
a6: string;
...
constructor(user: JustProps<User>) {...}
doSomething() { ... }
doSomething2() { ... }
doSomething3() { ... }
}
// it allows me to use it in this way
const user = new User({ name: 'aaa', age: 32, ... }); |
479173a
to
1c76afe
Compare
Thanks for suggesting this type. However, I have decided to pass on it for reasons outlined in the discussion here. |
I'd like to make a case for I'm doing a GraphQL API which calls a REST API. I'm also using @ObjectType()
class Launch {
@Field(() => ID)
id!: string;
@Field({ nullable: true })
site?: string;
@Field(() => Mission, { nullable: true })
mission!: Mission;
@Field(() => Rocket, { nullable: true })
rocket!: Rocket;
} When I fetch data from my REST API, the model is completely different and I need to map it to the GraphQL Type to properly return it within my GraphQL API. For instance, this is the method which makes the REST request: async fetchOne(id: string): Promise<Launch> {
const response = await this.get<RESTLaunch>(`launches/${id}`);
return launchReducer(response);
} And this is the function launchReducer(launch: RESTLaunch): Launch {
return new Launch({
id: String(launch.flight_number || 0),
site: launch.launch_site?.site_name,
mission: {
name: launch.mission_name,
smallPatchUrl: launch.links.mission_patch_small,
largePatchUrl: launch.links.mission_patch,
},
rocket: {
id: launch.rocket.rocket_id,
},
});
} As you can see, I'm passing a data structure that correctly maps the This is where the constructor(data: JustProps<Launch>) {
Object.assign(this, data);
} This is my case for including As a workaround, I believe I can achieve the same result by leveraging the current type definitions in type JustProps<Base> = ConditionalExcept<Base, Function>; |
Useful types. It's a pity they didn't accept 🥺 |
This type would be very useful until TypeScript offers a better way to handle named properties. microsoft/TypeScript#29526 |
No description provided.