or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

display-utilities.mddom-configuration.mdenvironment-utilities.mdequality-utilities.mdhtml-security.mdindex.mdnormalization.mdobject-utilities.mdreactive-flags.mdstring-transformations.mdtype-checking.md

equality-utilities.mddocs/

0

# Equality and Comparison

1

2

Deep equality checking and comparison utilities with special handling for complex data types including dates, arrays, objects, and symbols.

3

4

## Capabilities

5

6

### Deep Equality Comparison

7

8

Functions for performing deep equality checks that handle JavaScript's complex equality semantics.

9

10

```typescript { .api }

11

/**

12

* Perform deep loose equality comparison between two values

13

* Handles special cases for dates, symbols, arrays, and objects

14

* @param a - First value to compare

15

* @param b - Second value to compare

16

* @returns True if values are loosely equal

17

*/

18

function looseEqual(a: any, b: any): boolean;

19

20

/**

21

* Find index of value in array using loose equality comparison

22

* Uses looseEqual for comparison instead of strict equality

23

* @param arr - Array to search in

24

* @param val - Value to find

25

* @returns Index of value or -1 if not found

26

*/

27

function looseIndexOf(arr: any[], val: any): number;

28

```

29

30

**Usage Examples:**

31

32

```typescript

33

import { looseEqual, looseIndexOf } from "@vue/shared";

34

35

// Basic equality (same as === for primitives)

36

console.log(looseEqual(1, 1)); // true

37

console.log(looseEqual("hello", "hello")); // true

38

console.log(looseEqual(1, "1")); // false (different types)

39

40

// Date comparison (compares timestamps)

41

const date1 = new Date("2023-01-01");

42

const date2 = new Date("2023-01-01");

43

const date3 = new Date("2023-01-02");

44

45

console.log(looseEqual(date1, date2)); // true (same timestamp)

46

console.log(looseEqual(date1, date3)); // false (different timestamps)

47

console.log(date1 === date2); // false (different objects)

48

49

// Symbol comparison (always strict)

50

const sym1 = Symbol("test");

51

const sym2 = Symbol("test");

52

const sym3 = sym1;

53

54

console.log(looseEqual(sym1, sym2)); // false (different symbols)

55

console.log(looseEqual(sym1, sym3)); // true (same symbol)

56

57

// Array comparison (recursive)

58

const arr1 = [1, 2, { a: 3 }];

59

const arr2 = [1, 2, { a: 3 }];

60

const arr3 = [1, 2, { a: 4 }];

61

62

console.log(looseEqual(arr1, arr2)); // true (deep equal)

63

console.log(looseEqual(arr1, arr3)); // false (nested object differs)

64

console.log(arr1 === arr2); // false (different array objects)

65

66

// Object comparison (recursive)

67

const obj1 = {

68

name: "John",

69

age: 30,

70

hobbies: ["reading", "coding"],

71

birth: new Date("1993-01-01")

72

};

73

const obj2 = {

74

name: "John",

75

age: 30,

76

hobbies: ["reading", "coding"],

77

birth: new Date("1993-01-01")

78

};

79

const obj3 = {

80

name: "John",

81

age: 31,

82

hobbies: ["reading", "coding"],

83

birth: new Date("1993-01-01")

84

};

85

86

console.log(looseEqual(obj1, obj2)); // true (deep equal)

87

console.log(looseEqual(obj1, obj3)); // false (age differs)

88

89

// Nested structure comparison

90

const complex1 = {

91

users: [

92

{ id: 1, profile: { name: "Alice", tags: ["admin"] } },

93

{ id: 2, profile: { name: "Bob", tags: ["user"] } }

94

],

95

settings: { theme: "dark", notifications: true }

96

};

97

98

const complex2 = {

99

users: [

100

{ id: 1, profile: { name: "Alice", tags: ["admin"] } },

101

{ id: 2, profile: { name: "Bob", tags: ["user"] } }

102

],

103

settings: { theme: "dark", notifications: true }

104

};

105

106

console.log(looseEqual(complex1, complex2)); // true

107

108

// Array indexOf with loose equality

109

const mixedArray = [

110

1,

111

"hello",

112

{ name: "test" },

113

[1, 2, 3],

114

new Date("2023-01-01")

115

];

116

117

// Find equivalent values

118

console.log(looseIndexOf(mixedArray, 1)); // 0

119

console.log(looseIndexOf(mixedArray, { name: "test" })); // 2

120

console.log(looseIndexOf(mixedArray, [1, 2, 3])); // 3

121

console.log(looseIndexOf(mixedArray, new Date("2023-01-01"))); // 4

122

123

// Not found

124

console.log(looseIndexOf(mixedArray, { name: "other" })); // -1

125

console.log(looseIndexOf(mixedArray, [1, 2, 4])); // -1

126

```

127

128

### Equality Comparison Rules

129

130

**looseEqual** follows these rules in order:

131

132

1. **Strict Equality**: If `a === b`, return `true`

133

2. **Date Objects**: Compare using `getTime()` if both are dates

134

3. **Symbols**: Use strict equality (symbols are unique)

135

4. **Arrays**: Compare length first, then recursively compare each element

136

5. **Objects**: Compare key count first, then recursively compare each property

137

6. **Fallback**: Convert both to strings and compare

138

139

### Special Case Handling

140

141

**Date Comparison:**

142

```typescript

143

const d1 = new Date("2023-01-01T00:00:00.000Z");

144

const d2 = new Date("2023-01-01T00:00:00.000Z");

145

looseEqual(d1, d2); // true - compares timestamps

146

```

147

148

**Array vs Non-Array:**

149

```typescript

150

looseEqual([1, 2], "1,2"); // false - different types

151

looseEqual([], ""); // false - different types

152

```

153

154

**Object Property Order:**

155

```typescript

156

looseEqual({ a: 1, b: 2 }, { b: 2, a: 1 }); // true - order doesn't matter

157

```

158

159

**Missing vs Undefined Properties:**

160

```typescript

161

looseEqual({ a: 1 }, { a: 1, b: undefined }); // false - different key counts

162

```

163

164

**Circular References:**

165

```typescript

166

const circular1: any = { name: "test" };

167

circular1.self = circular1;

168

169

const circular2: any = { name: "test" };

170

circular2.self = circular2;

171

172

// Will cause maximum call stack exceeded error

173

// looseEqual(circular1, circular2); // ❌ Don't do this

174

```

175

176

### Performance Characteristics

177

178

- **Early Returns**: Exits quickly for strict equality and type mismatches

179

- **Length Checks**: Compares array/object sizes before deep comparison

180

- **Recursive**: Can handle deeply nested structures (limited by call stack)

181

- **No Caching**: Each comparison is independent (no memoization)

182

183

### Common Use Cases

184

185

**Form Validation:**

186

```typescript

187

function hasFormChanged(currentValues: any, originalValues: any) {

188

return !looseEqual(currentValues, originalValues);

189

}

190

```

191

192

**Array Operations:**

193

```typescript

194

function removeByValue(arr: any[], value: any) {

195

const index = looseIndexOf(arr, value);

196

if (index > -1) {

197

arr.splice(index, 1);

198

}

199

}

200

```

201

202

**Change Detection:**

203

```typescript

204

function shouldUpdate(newProps: any, oldProps: any) {

205

return !looseEqual(newProps, oldProps);

206

}

207

```

208

209

### Limitations

210

211

- **Circular References**: Will cause stack overflow

212

- **Function Comparison**: Functions are compared by reference, not implementation

213

- **Class Instances**: Compared as plain objects (only enumerable properties)

214

- **Prototype Chain**: Only checks own properties, ignores prototype

215

- **Performance**: Deep comparison can be expensive for large nested structures