-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Feature request: type-only members #18556
Comments
why not just use a name that does not show up in completion list, e.g. something that starts with a non-identifier character: type Field<T> = {
"#instance": T;
metadata: FieldMetadata;
}; |
This would invent non-standard syntax for something that would fool the IDE but not the compiler, Also, consider if TypeScript ever added a definite assignment rule - then this would have to be hacked around with |
To clarify - there is no valid value for the So instead of const PersonNameField = new Field<string>({fieldName: "name"}); one would have to use const PersonNameField = new Field<string>({fieldName: "name", instance: "John Smith"}); where the value "John Smith" would never be actually used. |
can you elaborate on the issue. not sure why you need to pass in an extra parameter? |
The idea is to define a schema using expressions, not types, in a DSL. This way the types are inferred and there is no repetition. Also, sometimes the schema might contain more specific information than the TypeScript type system (e.g. field lengths, number types, etc). E.g. namespace framework {
type Field<T> = {
name: string;
typeName: string;
instance: T;
};
type FieldSchema<D> = {[P in keyof D]: Field<any>};
type Schema<D extends FieldSchema<D>> = { fieldSchema: D };
export const makeSchema = <D extends FieldSchema<D>>(fieldSchema: D): Schema<D> => ({ fieldSchema: fieldSchema });
type FieldSchemaOfSchema<S extends Schema<any>> = S["fieldSchema"];
type InstanceTypeOfField<F extends Field<any>> = F["instance"];
export type SchemaType<S extends Schema<any>> = {[P in keyof FieldSchemaOfSchema<S>]: InstanceTypeOfField<FieldSchemaOfSchema<S>[P]>};
export const StringField: (name: string) => Field<string> = name => ({ name, instance: undefined as any as string, typeName: "string" });
export const IntField: (name: string) => Field<number> = name => ({ name, instance: undefined as any as number, typeName: "int" });
}
namespace schema {
export const PersonSchema = framework.makeSchema({
firstName: framework.StringField("firstName"),
lastName: framework.StringField("lastName"),
age: framework.IntField("age"),
});
export type Person = framework.SchemaType<typeof PersonSchema>;
}
namespace code {
console.log(JSON.stringify(schema.PersonSchema));
const person: schema.Person = {
firstName: "Magnus",
lastName: "Hiie",
age: 40 // "", // Types of property 'age' are incompatible. Type 'string' is not assignable to type 'number'.
};
console.log(JSON.stringify(person));
} produces: {"fieldSchema":{"firstName":{"name":"firstName","typeName":"string"},"lastName":{"name":"lastName","typeName":"string"},"age":{"name":"age","typeName":"int"}}}
{"firstName":"Magnus","lastName":"Hiie","age":40} Note the EDIT: simplified a little |
Is this related to or a duplicate of #17588? |
I agree that it would be nice to do this without adding a phantom property which is not intended to exist at runtime. Currently if you ever need an instance of the augmented type, you either have to make the property optional (which dilutes |
@magnushiie you may want to take a look at |
Thanks, @gcanti, I will take a look. My use case is actually a little bit more specific, but maybe I can get some ideas. |
Both of these projects also have these "phantom" properties: https://github.com/pelotom/runtypes has |
This might be something that could tie into associated types (?) |
This issue is especially bad where the false witnesses make the types unnecessarily covariant on the generic argument, whereas a type-only member or typedef would not impose covariance on the type. E.g. the following interface is now invariant on T: interface DoSomethingWith<T> {
public readonly whatCanIDoSomethingWithFalseWitness: T;
public doSomething(something: T) {
}
} |
Duplicate of #17588 |
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
The following pattern allows one to define run-time structures that also have a compile-time representation:
However, because
Field<T>
instances would be effectively singletons, the instance field is never going to be filled in because it's only used for compile-time type checking/inference.Therefore, I propose to have "type-only" members, e.g.:
readonly inspiration
This would mean that accessing the
instance
member in an expression context would result in an error (only type indexing is allowed).member types
The text was updated successfully, but these errors were encountered: