add test file for types
This commit is contained in:
		
							parent
							
								
									5d0da802b8
								
							
						
					
					
						commit
						f22dbb7036
					
				
							
								
								
									
										92
									
								
								tests/test-types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								tests/test-types.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,92 @@
 | 
			
		||||
/**
 | 
			
		||||
 * This file serves to validate the public TypeScript API for YJS.
 | 
			
		||||
 *
 | 
			
		||||
 * It is not included in `npm run lint` or any other automated type checking, but can be used
 | 
			
		||||
 * by those working on YJS types to ensure that the public-facing type interface remains valid.
 | 
			
		||||
 *
 | 
			
		||||
 * Any lines which are supposed to demonstrate statements that _would_ generate type errors
 | 
			
		||||
 * should be clearly marked with the type error that is expected to result, to provide a
 | 
			
		||||
 * negative test case.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import * as Y from "../dist/src/index";
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Typed maps
 | 
			
		||||
 *
 | 
			
		||||
 * - Key names are autocompleted in first parameter of `get` and `set`.
 | 
			
		||||
 * - `MapType` value types are constrained to valid Y.Map contents.
 | 
			
		||||
 */
 | 
			
		||||
type MyType = {
 | 
			
		||||
  foo: string;
 | 
			
		||||
  bar: number | null;
 | 
			
		||||
  baz?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Constructor argument keys & values are typechecked, and keys are autocompleted.
 | 
			
		||||
// Multiple items for each key and partial initialization are allowed.
 | 
			
		||||
const map = new Y.Map<MyType>([
 | 
			
		||||
  ["foo", ""],
 | 
			
		||||
  ["foo", "even better"],
 | 
			
		||||
  // ERROR: Type '["baz", number]' is not assignable to type '["foo", string] | ["bar", number | null] | ["baz", boolean | undefined]'.
 | 
			
		||||
  ["baz", 3],
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
// Entries are still allowed to be omitted, so get() still returns <type> | undefined.
 | 
			
		||||
const defaultMap = new Y.Map<MyType>();
 | 
			
		||||
 | 
			
		||||
// `json` has a type of `Partial<MyType>`
 | 
			
		||||
const json = defaultMap.toJSON();
 | 
			
		||||
 | 
			
		||||
// string | undefined
 | 
			
		||||
const fooValue = map.get("foo");
 | 
			
		||||
// literal "hi" (string)
 | 
			
		||||
const fooSet = map.set("foo", "hi");
 | 
			
		||||
// number | null | undefined
 | 
			
		||||
const barValue = map.get("bar");
 | 
			
		||||
// ERROR: Argument of type '"hi"' is not assignable to parameter of type 'number | null'.
 | 
			
		||||
const barSet = map.set("bar", "hi");
 | 
			
		||||
// ERROR: Argument of type '"bomb"' is not assignable to parameter of type 'keyof MyType'.
 | 
			
		||||
const missingGet = map.get("bomb");
 | 
			
		||||
// Escape hatch: get<any>()
 | 
			
		||||
const migrateGet = map.get<any>("extraneousKey");
 | 
			
		||||
 | 
			
		||||
// ERROR: Type '<type>' does not satisfy the constraint 'Record<string, MapValue>'.
 | 
			
		||||
const invalidMap = new Y.Map<{ invalid: () => void }>();
 | 
			
		||||
const invalidMap2 = new Y.Map<{ invalid: Blob }>();
 | 
			
		||||
// Arbitrarily complex valid types are still allowed
 | 
			
		||||
type ComplexType = {
 | 
			
		||||
  n: null;
 | 
			
		||||
  b: boolean;
 | 
			
		||||
  s: string;
 | 
			
		||||
  i: number;
 | 
			
		||||
  u: Uint8Array;
 | 
			
		||||
  a: null | boolean | string | number | Uint8Array[];
 | 
			
		||||
};
 | 
			
		||||
const complexValidType = new Y.Map<
 | 
			
		||||
  ComplexType & { nested: ComplexType & { deeper: ComplexType[] } }
 | 
			
		||||
>();
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Default behavior
 | 
			
		||||
 *
 | 
			
		||||
 * Provides basic typechecking over the range of possible map values.
 | 
			
		||||
 */
 | 
			
		||||
const untyped = new Y.Map();
 | 
			
		||||
 | 
			
		||||
// MapValue | undefined
 | 
			
		||||
const boop = untyped.get("default");
 | 
			
		||||
// Still validates value types: ERROR: Argument of type '() => string' is not assignable to parameter of type 'MapValue'.
 | 
			
		||||
const moop = untyped.set("anything", () => "whoops");
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * `any` maps (bypass typechecking)
 | 
			
		||||
 */
 | 
			
		||||
const anyMap = new Y.Map<any>();
 | 
			
		||||
 | 
			
		||||
// any
 | 
			
		||||
const fooValueAny = anyMap.get("foo");
 | 
			
		||||
// literal "hi" (string)
 | 
			
		||||
const fooSetAny = anyMap.set("foo", "hi");
 | 
			
		||||
// Allowed because `any` unlocks cowboy mode
 | 
			
		||||
const barSetAny = anyMap.set("bar", () => "hi");
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user